无法使notify()与使用线程的Bouncing Balls一起使用

时间:2013-09-15 02:30:40

标签: java multithreading

我正在尝试使用一个线程来控制弹跳球。我可以添加球,删除球,暂停运动,但当我尝试恢复弹跳球的运动时,notify()/ notifyAll()不起作用。我只想要一个线程来控制在List中添加的球的移动。我很感激一个简单的解释,因为我是一个完整的新手。这是代码:

 ************************************************
 public class BounceBallApp extends JApplet {
 public BounceBallApp() {
 add(new BallControl());
 }

 public static void main(String[] args) {
     BounceBallApp applet = new BounceBallApp();
     JFrame frame = new JFrame();
     frame.add(applet); //new line added as per the reference
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setTitle("Assig_1_Base");
     frame.add(applet, BorderLayout.CENTER);
     frame.setSize(400, 320);
     frame.setVisible(true);
   }
}
***************************************************************
 public class BallControl extends JPanel {

private BallPanel ballPanel = new BallPanel();
private JButton jbtSuspend = new JButton("Suspend");
private JButton jbtResume = new JButton("Resume");
private JScrollBar jsbDelay = new JScrollBar();
private JButton jbtAddBall = new JButton("+1");
private JButton jbtDeleteBall = new JButton("-1");

    public BallControl() {

    JPanel panel = new JPanel();
    panel.add(jbtSuspend);
    panel.add(jbtResume);
    panel.add(jbtAddBall);
    panel.add(jbtDeleteBall);
    ballPanel.add();


   ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
   jsbDelay.setOrientation(JScrollBar.HORIZONTAL);
   ballPanel.setDelay(jsbDelay.getMaximum());
   setLayout(new BorderLayout());
   add(jsbDelay, BorderLayout.NORTH);
   add(ballPanel, BorderLayout.CENTER);
   add(panel, BorderLayout.SOUTH);

  // Register listeners
   jbtSuspend.addActionListener(new ActionListener() {
    @Override
    public synchronized void actionPerformed(ActionEvent e) {
        ballPanel.suspend();
     }
    });
  jbtResume.addActionListener(new ActionListener() {
   @Override
   public synchronized void actionPerformed(ActionEvent e) {
       ballPanel.resume();
    }
   });

  jbtAddBall.addActionListener(new ActionListener() {
   @Override
    public synchronized void actionPerformed(ActionEvent e) {
      ballPanel.add();
    }
  });
  jbtDeleteBall.addActionListener(new ActionListener() {
    @Override
    public synchronized void actionPerformed(ActionEvent e) {
      ballPanel.delete();
    }
  });
 jsbDelay.addAdjustmentListener(new AdjustmentListener() {
   @Override
   public void adjustmentValueChanged(AdjustmentEvent e) {
    ballPanel.setDelay(jsbDelay.getMaximum() - e.getValue());
  }
 });
}

}


public class BallPanel extends JPanel {

  private int delay = 10;   
  private List<Ball> ballsArray = Collections.synchronizedList(new ArrayList());
  //protected List<Ball> ballsArray = new ArrayList<>();
  private int radius = 5; 
  boolean threadSuspended = false;

  public BallPanel() {
    start();
  }

  protected void start(){
   Thread t;
     t = new Thread(){
        @Override
         public void run(){
            System.out.println("*************");
             while (true){
                repaint();
                try {
                    Thread.sleep(delay);
                       synchronized(this){
                        if (threadSuspended==true) {wait();}
                       }
                } catch (InterruptedException e){
                    e.getMessage();
                }
            }
        }
   };

    t.start();
 }

 @Override
  protected void paintComponent(Graphics g) {
  super.paintComponent(g);

    for (Ball ball : ballsArray){

        g.setColor(ball.color);

                if (ball.x < 0 || ball.x > getWidth()) 
                  ball.dx *= -1;
        if (ball.y < 0 || ball.y > getHeight()) 
          ball.dy *= -1;

                ball.x += ball.dx;
        ball.y += ball.dy;
        g.fillOval(ball.x - radius, ball.y - radius, radius * 2, radius * 2);
    }   
}

public synchronized void suspend() {
  threadSuspended = true;
}

public synchronized void resume() {
  threadSuspended = false;
  notify();
}

public void setDelay(int delay) {
  this.delay = delay;
}
public void add(){
  if (threadSuspended==false)  ballsArray.add(new Ball());
}

public void delete(){
  if (ballsArray.size() > 0 && threadSuspended==false)
      ballsArray.remove(ballsArray.size() - 1); // Remove the last ball

 }
}

**************************************************
public class Ball  {

 int x = 0; 
 int y = 0;
 int dx = 2;
 int dy = 2;
 Color color = new Color(random(255),random(255),random(255));

     public static int random(int maxRange) {
     return (int) Math.round((Math.random() * maxRange));
  }

}

1 个答案:

答案 0 :(得分:1)

您有“背景”问题......

您在Thread ...

的上下文中声明了BallPane

因此,当您致电wait()时,您实际上是在wait()上呼叫t

Thread t;
t = new Thread(){
    @Override
    public void run(){
        /*...*/
        // this = t
        synchronized(this){
            // This is the same as saying
            // this.wait() or t.wait();
            if (threadSuspended==true) {wait();}
        }
    }
};

但是当您致电notify时,您正在调用BallPane的{​​{1}}方法......

notify

因此,public synchronized void resume() { threadSuspended = false; // This is the same as this.notify or BallPane.this.notify() notify(); } 正在等待t的监视器锁定,并且您在监视器锁定时调用t的通知...意味着永远不会通知BallPane

如果您使用共享锁而不是......

t