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