试图让守卫的街区工作

时间:2016-04-23 23:03:48

标签: java multithreading

我不明白为什么我的代码无法正常工作。我希望第一个Thread等待4秒,第二个Thread设置一个共享的布尔值" joy"为了真实,那么第一个Thread打印出来" Joy已经实现了!"。

当我运行代码时,我得到了这个输出:

  

"没有欢乐......"

     

"通知Joy"

然后它冻结并且不会继续。如果我的理解是正确的,从我的notifyJoy()方法调用的notifyAll()方法应该从它的wait()唤醒t1然后,因为共享的静态布尔变量joy现在是真的," Joy已经实现&#34!;应该打印到控制台。

我使用的是甲骨文" Java教程",第13章:这里是指向特定部分的链接:Java Tutorial Website。我已经离开了他们所拥有的东西并做了一个小例子,但我似乎无法弄清楚我做错了什么。任何帮助,将不胜感激。以下是我的代码的完整副本供您参考:

public class JoyTime {

    public static void main(String[] args) {
        JoyRider j1 = new JoyRider(false);
        JoyRider j2 = new JoyRider(true);

        Thread t1 = new Thread(j1, "J1");
        Thread t2 = new Thread(j2, "J2");

        t1.start();

        try {
            Thread.sleep(4000);
        }
        catch (InterruptedException e) {}

        t2.start();
    }
}

class JoyRider implements Runnable {

    private static boolean joy = false;
    private boolean flag;

    public JoyRider(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        synchronized(this) {
            if (flag) {
                notifyJoy();
            }
            else {
                while (!joy) {
                    System.out.println("No Joy Yet...");
                    try {
                        this.wait();
                    }
                    catch (InterruptedException e) {}
                }
                System.out.println("Joy has been achieved!");
            }
        }
    }

    public synchronized void notifyJoy() {
        System.out.println("Notifying Joy");
        joy = true;
        notifyAll();
    }
}

2 个答案:

答案 0 :(得分:4)

您在不同的监视器上调用wait()notifyAll(),更具体地说,在两个不同的JoyRider实例的内置监视器上调用。

如果您引入专用锁定对象:

private static final Object LOCK = new Object();

并稍微更改一下run()方法:

synchronized (LOCK) {
   if (flag) {
      System.out.println("Notifying Joy");
      JOY = true;
      LOCK.notifyAll();
   }
   else {
      while (!JOY) {
         System.out.println("No Joy Yet...");
         try {
            LOCK.wait();
         }
         catch (InterruptedException e) {}
      }
      System.out.println("Joy has been achieved!");
   }
}

您应该能够以正确的顺序看到所有预期的打印件。

答案 1 :(得分:3)

首先查看notifyAll的{​​{3}}。

  

唤醒正在等待此对象的监视器的所有线程。

强调我的。您有两个JoyRiderj1j2。他们每个人都会自己调用wait。因此,当您调用notifyAll时,您只是通知在该实例上等待的线程(即。j1仅通知在j1上等待的线程,而j2仅通知等待的线程在j2)。

您可以通过同步和锁定静态对象来解决此问题。因此,添加private static final Object LOCK = new Object();,将您的方法更改为synchronize(LOCK),并在notifyAll而不是wait上调用LOCKthis