title: Java | How can I make one of the threads sleep while the other ones are still running?
body: <p>I'm currently working on an application which uses the draw function to animate "bouncing images" in a JPanel. To accomplish it I had to learn to use threads. When I  used them in my code someone recommended that instead of using threads directly I can use stuff like Executor framework and ExecutorService. </p>
  
  <p>Right now my problem is that when adding new images I need to make sure that they don't get created inside each other. When the program detects that they would be intersecting it should wait some amount of time, while all the other threads keep running, so images are still getting moved and drawn in current positions.
  What happens however is that when I make one of the threads sleep to wait for a spot to be empty the whole program seems to freeze. The only thing that seems to be running is the image moving function.</p>
  
  <p><a href="https://gist.github.com/AnthonyGu55/1606a7faf693a028383c099d827acfa5" rel="nofollow noreferrer">Code in a Github Gist</a></p>
  
  <p>Here is the code:</p>
  
  <p>This is the BouncingImages class</p>
  
  <pre><code>
  /* NOTE: requires MyImage.java */
  
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.util.ArrayList;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.Future;
  
  
  import javax.swing.*;
  
  
  public class BouncingImages extends JFrame implements ActionListener {
  
      public static void main(String[] args) {
          new BouncingImages();
      }
  
      static boolean imagesLoaded = true;
      JPanel resetPanel   = new JPanel();
      JPanel runningPanel = new JPanel();
      JPanel pausedPanel  = new JPanel();
      JPanel btnPanel     = new JPanel();
      public static AnimationPanel animationPanel;
      ArrayList &lt;MyImage&gt; imageList = new ArrayList &lt;MyImage&gt;();
      private volatile boolean stopRequested = false; //maybe should use AtomicBoolean
      boolean isRunning = false;
      boolean isReset = true;
      ExecutorService service = Executors.newCachedThreadPool();
      Future f;
  
      //here is the part of the code responsible for creating a JFrame
      BouncingImages() {
  
          //set up button panel
          JButton btnStart  = new JButton("Start");
          JButton btnResume = new JButton("Resume");
          JButton btnAdd    = new JButton("Add");
          JButton btnAdd10  = new JButton("Add 10");
          JButton btnStop   = new JButton("Stop");
          JButton btnReset  = new JButton("Reset");
          JButton btnExit   = new JButton("Exit");
  
          btnStart.addActionListener(this);
          btnResume.addActionListener(this);
          btnAdd.addActionListener(this);
          btnAdd10.addActionListener(this);
          btnStop.addActionListener(this);
          btnReset.addActionListener(this);
          btnExit.addActionListener(this);
  
          resetPanel.add(btnStart);
  
          runningPanel.add(btnAdd);
          runningPanel.add(btnAdd10);
          runningPanel.add(btnStop);
  
          pausedPanel.add(btnResume);
          pausedPanel.add(btnReset);
  
          animationPanel = new AnimationPanel();
  
          resetButtons();
          this.add(btnPanel, BorderLayout.SOUTH);
          this.add(animationPanel);
          this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          this.pack(); //since the JPanel is controlling the size, we need pack() here.
          this.setLocationRelativeTo(null);    //after pack();
          this.setVisible(true);
      }
  
      //I use different JPanels with designated buttons to make them display different buttons when the program is running, paused or completely restarted.
      public void resetButtons() {
          btnPanel.updateUI();
          if (isReset) {
              btnPanel.removeAll();
              btnPanel.add(resetPanel, BorderLayout.SOUTH);
          } else {
              if (isRunning) {
                  btnPanel.removeAll();
                  btnPanel.add(runningPanel, BorderLayout.SOUTH);
              }
              if (!isRunning) {
                  btnPanel.removeAll();
                  btnPanel.add(pausedPanel, BorderLayout.SOUTH);
              }
          }
      }
  
      //ActionListener for Buttons
      @Override
      public void actionPerformed(ActionEvent e) {
          if (e.getActionCommand().equals("Start")) {
              startAnimation();
              isRunning = true;
              isReset = false;
              resetButtons();
          }
          if (e.getActionCommand().equals("Resume")) {
              startAnimation();
              isRunning = true;
              resetButtons();
          }
          if (e.getActionCommand().equals("Add")) {
              addImage();
  
          }
          if (e.getActionCommand().equals("Add 10")) {
              for(int i = 0; i &lt;10; i++) {
                  addImage();
                  startAnimation();
              }
  
          }
          if (e.getActionCommand().equals("Stop")) {
              pauseAnimation();
              isRunning = false;
              resetButtons();
          }
          if (e.getActionCommand().equals("Reset")) {
              imageList.clear();
              repaint();
              isReset = true;
              resetButtons();
          }
          if (e.getActionCommand().equals("Exit")) {
              System.exit(0);
          }
  
      }
      //This function starts all the animations using the Runnable AnimationThread
      void startAnimation() {
          //this starts the program
          if (f == null) {
              f = service.submit(new AnimationThread());
          }
          //this starts the program after it got paused
          else if (f.isCancelled()) {
              f = service.submit(new AnimationThread());
          }
      }
      //this pauses all the animations
      void pauseAnimation() {
          f.cancel(true);
      }
  
      //here is the part of the code that I have problems with. I'm not sure how to make the program wait for a spot to be empty while all the other threads are running rather than pausing them all.
      void addImage(){
          int i = 0;
          MyImage image;
          while (true) {
              image= new MyImage("image.png");
              if (checkCollision(image)) {
                  if(i &gt; 100){
                      System.out.println("Something went wrong");
                      System.exit(0);
                  }
                  try {
                      i++;
                      Thread.sleep(50);
                  } catch (InterruptedException e) {}
              } else {
                  System.out.println("image added");
                  break;
              }
          }
  
          imageList.add(image);
      }
  
      //this part of the program does all the image moving. It uses the function move image from the MyImage class and a checkCollision function from this class.
      void moveAllImages() {
          for (MyImage image : imageList) {
              image.moveImage(animationPanel);
              image.calculatePoints();
              checkCollision(image);
          }
      }
  
      //this checks all the collisions with other images. It can be used for checking if a image can be created in some spot and also for all the bouncing callculations
      boolean checkCollision(MyImage currentImage){
  
          if(imageList.isEmpty()) return false;
          for(MyImage im : imageList){
              if(currentImage == im) continue;
  
              if(currentImage.intersects(im)){
                  if(im.contains(currentImage.ml) || im.contains(currentImage.mr)){
                      currentImage.undoMove();
                      currentImage.vx = -currentImage.vx;
                      return true;
                  }
              }
  
              if(im.contains(currentImage.mt) || im.contains(currentImage.mb)){
                  currentImage.undoMove();
                  currentImage.vy = - currentImage.vy;
                  return true;
              }
  
              if(currentImage.contains(im.ml) || currentImage.contains(im.mr)){
                  currentImage.undoMove();
                  currentImage.vx = -currentImage.vx;
                  return true;
              }
  
              if (im.contains(currentImage.tl) || im.contains(currentImage.tr) || im.contains(currentImage.bl) || im.contains(currentImage.br)) {
                  currentImage.undoMove();
                  currentImage.vx *= -1;
                  currentImage.vy *= -1;
                  return true;
              }
          }
  
          return false;
      }
  
  
  
  
  
      //This class does drawing graphics and nothing else
      public class AnimationPanel extends JPanel {
  
          AnimationPanel() {
              this.setBackground(Color.BLACK);
              Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
              this.setPreferredSize(new Dimension((int) screenSize.getWidth() / 2, (int) screenSize.getHeight() / 2));
          }
  
  
          @Override
          public void paintComponent(Graphics g) {
              super.paintComponent(g);
              for (MyImage im : imageList) {
                  g.drawImage(im.image, im.x, im.y, im.width, im.height, null);
              }
          }
      }
  
      //this is the Runnable AnimationThread which does all the image moving and repainting.
      private class AnimationThread implements Runnable {
          @Override
          public void run() {
              while (!f.isCancelled()) {
                  moveAllImages();
                  animationPanel.repaint();
  
                  try {
                      Thread.sleep(5);
                  }
                  catch (InterruptedException e) {
                      System.out.println(e.getMessage());
                      f.cancel(true);
                  }
  
              }
  
          }
  
      }
  }
  </code></pre>
  
  <p>This is the MyImage class</p>
  
  <pre><code>package bouncer;
  
  import java.awt.Color;
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.image.BufferedImage;
  import java.io.File;
  import java.io.IOException;
  import javax.imageio.ImageIO;
  
  
  //NOTE: This class requires BouncingImages.java
  
  /* This class combines an image with a rectangle
   * which allows for easy movement and collision detection
   */
  class MyImage extends Rectangle {
      //this gives it an x,y,width,height
  
      static int biggestDim = 0;
      BufferedImage image;
      Color color = Color.RED;
      //these are the speeds of movement
      int vx = 1;
      int vy = 1;
      int lastx = -1;
      int lasty = -1;
  
      Point ctr, tl, tr, bl, br, ml, mr, mt, mb;
  
      MyImage(String filename) {
  
          vx = (int) (Math.random() * 5 + 1);
          vy = (int) (Math.random() * 5 + 1);
  
          //load the image
          try {
              image  = ImageIO.read(new File(filename));
              width  = image.getWidth(null);
              height = image.getHeight(null);
          }
          catch (IOException e) {
              System.out.println("ERROR: image file \"" + filename + "\" not found");
              //e.printStackTrace();
              BouncingImages.imagesLoaded = false;
              width                       = 100 + (int) (Math.random() * 100);
              height                      = width - (int) (Math.random() * 70);
              color                       = Color.getHSBColor((float) Math.random(), 1.0f, 1.0f);    // a quick way to get random colours
              //System.exit(0);
          }
  
          //update the variable containing the biggest dimension
          if (width &gt; biggestDim) biggestDim = width;
          if (height &gt; biggestDim) biggestDim = height;
  
          calculatePoints();
      }
  
      void calculatePoints() {
          //Calculate points
          //corners
          tl = new Point(x, y);
          tr = new Point(x + width, y);
          bl = new Point(x, y + height);
          br = new Point(x + width, y + height);
          //center
          ctr = new Point(x + width / 2, y + height / 2);
          //mid points of sides
          ml = new Point(x, y + height / 2);
          mr = new Point(x + width, y + height / 2);
          mt = new Point(x + width / 2, y);
          mb = new Point(x + width / 2, y + height);
      }
  
      void moveImage(BouncingImages.AnimationPanel panel) {
          lastx = x;
          lasty = y;
          x += vx;
          y += vy;
          if (x &lt; 0 &amp;&amp; vx &lt; 0) {
              x  = 0;
              vx = -vx;
          }
          if (y &lt; 0 &amp;&amp; vy &lt; 0) {
              y  = 0;
              vy = -vy;
          }
          if (x + width &gt; panel.getWidth() &amp;&amp; vx &gt; 0) {
              x  = panel.getWidth() - width;
              vx = -vx;
          }
          if (y + height &gt; panel.getHeight() &amp;&amp; vy &gt; 0) {
              y  = panel.getHeight() - height;
              vy = -vy;
          }
      }
  
      void undoMove() {
          if (lastx &gt; 0) {
              x = lastx;
              y = lasty;
          }
          lastx = lasty = -1;
      }
  }
  </code></pre>