Java 无法使notify()使用线程处理弹跳球

Java 无法使notify()使用线程处理弹跳球,java,multithreading,Java,Multithreading,我试图用一根线来控制弹跳球。我可以添加球、删除球、暂停移动,但当我尝试恢复弹跳球的移动时,notify()/notifyAll()不起作用。我只需要一个线程来控制添加到列表中的球的移动。我希望能有一个简单的解释,因为我是一个完全的新手。代码如下: ************************************************ public class BounceBallApp extends JApplet { public BounceBallApp() { add

我试图用一根线来控制弹跳球。我可以添加球、删除球、暂停移动,但当我尝试恢复弹跳球的移动时,notify()/notifyAll()不起作用。我只需要一个线程来控制添加到列表中的球的移动。我希望能有一个简单的解释,因为我是一个完全的新手。代码如下:

 ************************************************
 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());
  }
 });
}
}


公共类BallPanel扩展了JPanel{
专用int延迟=10;
private List ballsArray=Collections.synchronizedList(新的ArrayList());
//受保护列表ballsArray=new ArrayList();
私有整数半径=5;
布尔值=false;
公共事务委员会(){
start();
}
受保护的void start(){
螺纹t;
t=新线程(){
@凌驾
公开募捐{
System.out.println(“****************”);
while(true){
重新油漆();
试一试{
睡眠(延迟);
已同步(此){
如果(threadSuspended==true){wait();}
}
}捕捉(中断异常e){
e、 getMessage();
}
}
}
};
t、 start();
}
@凌驾
受保护组件(图形g){
超级组件(g);
对于(球: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、 圆角椭圆(球.x-半径,球.y-半径,半径*2,半径*2);
}   
}
公共同步的void suspend(){
threadSuspended=true;
}
公共同步无效恢复(){
threadSuspended=false;
通知();
}
公共无效设置延迟(整数延迟){
延迟=延迟;
}
公共无效添加(){
如果(threadSuspended==false)ballsArray.add(newball());
}
公共作废删除(){
if(ballsArray.size()>0&&threadSuspended==false)
ballsArray.remove(ballsArray.size()-1);//移除最后一个球
}
}
**************************************************
公共班级舞会{
int x=0;
int y=0;
int dx=2;
int-dy=2;
颜色=新颜色(随机(255)、随机(255)、随机(255));
公共静态int随机(int最大范围){
返回(int)Math.round((Math.random()*maxRange));
}
}

您有一个“上下文”问题

您可以在
BallPane
的上下文中声明
线程

因此,当您调用
wait()
时,实际上是在
t
上调用
wait()

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
notify
方法

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

如果您使用共享锁,则会更好

public class BallPanel extends JPanel {
    protected static final Object SUSPEND_LOCK = new Object();

    /*...*/

    Thread t;
    t = new Thread(){
        @Override
        public void run(){
            /*...*/
            synchronized(SUSPEND_LOCK ){
                if (threadSuspended==true) {SUSPEND_LOCK.wait();}
            }
        }
    };

    /*...*/

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

任何人都请,因为我对这个问题完全失望。请帮忙!!!我想大多数人不会通读所有的代码。只张贴相关部分。你试过什么?错误在哪里?您确定代码正在通过必要的位置吗?可能会在
resume()
方法和执行
wait()
的位置插入一些
System.out.println()
消息,以便您知道发生了什么,线程何时停止等待以及是否收到通知。@Adam Arnold试图使用列表在帧中添加弹跳球。有两个按钮“暂停”和“恢复”设置布尔标志。Suspend使线程进入wait()状态,但当我使用重置布尔标志的“Resume”按钮时,它并没有通知处于等待状态的线程。@jbx Resume()只是重置布尔标志并使用notify()方法。但框架中的球仍处于悬挂状态。我还尝试在不同的地方使用System.out.println(),你是对的,resume()中的notify()对start()中的run()没有任何影响。我该怎么办?我应该在这里改变什么逻辑?@MadProgrammer。。非常感谢你。它现在工作得很好。“我本该希望塔茨能大获全胜”,因为当我在发帖时,我希望你能回答我的帖子&你回答了:)。你关于使用一个线程而不是多个线程的回答对我帮助很大。但是看看我的代码——你认为这真的是一种糟糕的方法吗?我很想使用
javax.swing.Timer
,因为你可以很容易地停止并重新启动它们,但这就是我;)是的,你完全正确:)。我有相同的代码与定时器,这是完美的工作。但是想尝试一下。@CompleteDiot顺便说一句,与其创建那样的匿名类,还可以简单地使
BallPanel
extend
Runnable
,并将
run()
方法作为
BallPanel
的一种方法移到外部,这会使
this.wait()
起作用。
start()
方法随后将执行
Thread t=new Thread(此操作);t、 start()。这将消除对
SUSPEND\u LOCK
对象的需要。@jbx的功能完全相同吗?这两种方法的缺点/优点是什么?另外,我想知道你对我尝试的代码的看法。我怎样才能改进它?是的,实现Runnable取消了对lock对象的需要。我尝试了你的建议并成功地运行了代码
public class BallPanel extends JPanel {
    protected static final Object SUSPEND_LOCK = new Object();

    /*...*/

    Thread t;
    t = new Thread(){
        @Override
        public void run(){
            /*...*/
            synchronized(SUSPEND_LOCK ){
                if (threadSuspended==true) {SUSPEND_LOCK.wait();}
            }
        }
    };

    /*...*/

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