为什么notifyAll()在这个简单的情况下不会恢复其他线程?

时间:2014-11-08 21:14:01

标签: java multithreading concurrency

我是Java并发新手。我有一个简单的对象,有3个方法,每个方法对应3个不同线程运行的代码。为什么在这种情况下notifyAll()语句不释放其他两个线程中的wait?

public class Main {
static class Obj {
      synchronized void t1 () {
          System.out.println("T1 ran");
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          notifyAll();
      }
     synchronized void t2 () {
         try {
             wait();
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println("T2 ran");
     }
    synchronized void t3() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("T3 ran");
    }
}

public static void main(String[] args) {
    final Obj o = new Obj();
    new Thread(new Runnable() {
        @Override
        public void run() {
            o.t1();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            o.t2();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            o.t3();
        }
    }).start();
}}

我期待: T1跑了 ~~暂停1秒~~ T2跑了 T3跑了

我得到了: T1跑了

3 个答案:

答案 0 :(得分:6)

Thread.sleep不会以wait的方式释放或放松任何锁定,因此同步仍然完全有效,并且其他线程不会被允许在其期间输入其方法睡觉。

如果您更换

Thread.sleep(1000);

wait(1000);

其他线程将被允许捕获相同的锁,输入方法,开始等待,样本将按预期工作。

答案 1 :(得分:3)

在同一个实例中,您的三种方法是synchronized。并且Thread#sleep(..)不会释放synchronized获取的锁定。因此,执行t1的线程获取锁定,休眠一秒,唤醒,调用notifyAll()并完成。

然后你的另外两个线程在执行时转弯并调用wait()。但是没有任何东西可以通知他们,所以你的申请会阻止。

你有一个竞争条件。更改启动线程的顺序或运行它,就像您有足够的时间一样,并且您可能会看到不同的行为。

答案 2 :(得分:3)

如果我是正确的,方法t2和t3的线程不能进入方法,因为线程t1一直锁定对象,就像同步方法一样。到t2和t3实际运行时,notifyAll()已经发生了,所以他们永远等待:(

您应首先尝试启动t2和t3,然后尝试启动t1。

正如已经指出的那样。 Thread.sleep()不释放任何锁或监视器,因此其他线程无法输入该方法,因为它被标记为synchronized:Thread.sleep()