我是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跑了
答案 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()