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



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

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运行

Thread.sleep不会像wait那样释放或放松任何锁,因此同步仍然完全有效,其他线程在睡眠期间将不允许进入其方法。

如果更换

Thread.sleep(1000);

带有

wait(1000);

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

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

你应该试着先从t2和t3开始,然后再从t1开始。

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

您的三个方法是同一实例上的synchronized。并且CCD_ 4不释放CCD_。所以执行t1的线程获取锁,休眠一秒钟,唤醒,调用notifyAll()并完成。

然后,您的另外两个线程分别轮流执行并调用wait()。但是没有任何东西可以通知他们,所以你的应用程序会被阻止。

你有比赛条件。更改启动线程的顺序,或者像有足够的时间一样运行线程,您可能会看到不同的行为。

最新更新