我的代码中的Wait()和NotifyAll()在for循环中不起作用

时间:2013-06-03 17:24:15

标签: java multithreading

我有这段代码:

private int           delay;
private int           x,y,R;
private int           dx=3 , dy=3;
private JLabel    box;
private Ball twin;
boolean isWaiting=false;
private  void  moveStep(){
    Dimension size= box.getSize();
    if (x<=0)
    {
        BounceTest.updateSide(0, BounceTest.getSideValue(0) + 1);
        dx = -dx;
        if(!isWaiting)
            twin.isWaiting=false;
            this.notifyAll();
    }


    if(x+2*R >=size.width){         // Bounce
        synchronized(BounceTest.sides[1])
        {
            BounceTest.updateSide(1, BounceTest.getSideValue(1) + 1);
            dx = -dx;
            this.notifyAll();
        }   
    }
    if (y<=0  ||  y+2*R >=size.height)
        dy = -dy;
    x += dx;
    y += dy;

}
public  synchronized void  run(){
    Color  bg = box.getBackground();
    Graphics  g = box.getGraphics();
    for (int i=0; i<5000; i++){

        draw(g,  Color.blue);                        // draw
        try {
            Thread.sleep(delay);                 // sleep
        } catch(InterruptedException e){}
        if(isWaiting)
        {
            System.out.println("ss1");
            try { 
                synchronized (twin) {
                    twin.wait(); 
                }

                }   catch(InterruptedException e) { }
            System.out.println("ss2");
        }
        draw(g, bg);                                     // delete
        moveStep();

    }
    g.dispose();
}

我有两个假设由同一个代码运行的线程,一个应该在twin.wait()方法中转到run()而另一个应该在{{{}}中调用NotifyAll() 1}}方法,但问题是当有一个for它没有调用moveStep()时,当我删除for它调用它时,为什么这样以及我如何解决它?

4 个答案:

答案 0 :(得分:0)

问题是你正在做等待的双胞胎(这使得线程在对象上睡眠)并且当你想要唤醒那个线程时你正在使用通知“this”。

您应该使用以下两个选项中的一个来更改代码:

选项1

更改:

this.notifyAll();

twin.notifyAll();

选项2:

synchronized (twin) {
  twin.wait();
}

synchronized (this) {
  this.wait();
}

答案 1 :(得分:0)

您的代码中存在一些不一致之处。

首先,你应该只对你实际同步的(an)对象调用notify或notifyAll,而不是其他对象(否则你会得到IllegalMonitorStateException)。

在BounceTest.sides [1]上进行同步,然后修改块内的一侧也可能会让你遇到麻烦,这取决于updateSide是否实际将对象[1]中的对象替换为另一个对象,或者只是修改了一些字段。对象(这没关系)。

此外,您通常不应该有一个空的catch块。即使对于InterruptedExceptions,当你认为它们不应该出现在你的程序中时:至少将它们输出到日志文件中(或者在简单程序的控制台上输出它们),这样你就知道什么时候出错了。

你似乎有一个isWaiting变量 - 但是我们所看到的是它被设置为false(如果另一个线程中的一个已经为假)。

然后,你的run方法被同步(这就像一个synchronized(this) - 块),你永远不会在这个方法(或moveStep)中等待this。这意味着另一个线程没有机会进入其synchronized(twin)块,两个线程将相互阻塞。

您的代码可能存在其他问题,但请从这些问题开始,然后回电并显示结果。

答案 2 :(得分:0)

我不知道“isWaiting”标志何时发生变化。应始终调用NotifyAll()(如果您的代码可以通过该行),但如果您没有持有您调用NotifyAll()的对象的监视器,则没有任何意义;我想你要等到每个移动完成,所以我猜你应该叫“twin.notifyAll()”而不是“this.notifyAll()”,因为你的主线程正在等待“双胞胎”的监视器没有一个

答案 3 :(得分:0)

另一个问题是在isWaiting之外读取synchronized。 Java内存模型不保证变量对其他线程可见。您可以通过两种方式解决此问题。您可以使变量volatile,这可以确保变量始终刷新到主内存,而不是CPU l2 / l3缓存。您还可以在synchronized语句中读取/操作变量。这可以保证变量的任何更改对于同步锁定的任何其他线程都是可见的。

相关问题