2

我有这个代码:

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()中调用,但问题是当有一个 for 它不调用时,当我删除因为它调用它,为什么会这样,我该如何解决它?NotifyAll()moveStep()NotifyAll()

4

4 回答 4

0

问题是您正在等待双胞胎(这使线程在对象双胞胎上休眠)并且当您想要唤醒该线程时,您正在使用“this”上的通知。

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

选项1

更改:

this.notifyAll();

twin.notifyAll();

选项 2:

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

synchronized (this) {
  this.wait();
}
于 2013-06-03T17:47:43.017 回答
0

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

首先,您应该只在您实际同步的(一个)对象上调用 notify 或 notifyAll,而不是其他对象(否则您将获得 IllegalMonitorStateException)。

在 BounceTest.sides[1] 上同步,然后修改块内的边也可能会给您带来麻烦,这取决于 updateSide 是否实际上将边 [1] 中的对象交换为另一个对象,或者只是修改对象中的某些字段(这没关系)。

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

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

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

您的代码可能还有其他问题,但从这些开始,然后回调并显示您的结果。

于 2013-06-03T17:48:22.753 回答
0

我不知道“isWaiting”标志何时更改。NotifyAll() 应该总是被调用(如果你的代码可以通过那一行),但如果你不持有你正在调用 NotifyAll() 的对象的监视器,它没有任何意义;我想你想等到每个移动完成,所以我想你应该调用“twin.notifyAll()”而不是“this.notifyAll()”,因为你的主线程正在等待“twin”的监视器不拥有一个.

于 2013-06-03T17:48:33.070 回答
0

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

于 2013-06-03T17:53:42.930 回答