以下代码在SCJP6书中
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}
先前的代码不会导致死锁,因为线程a和b都锁定b(在相应的同步块中)?
我遗失了一些东西,但不太确定它是什么。
答案 0 :(得分:6)
最有可能的执行如下:
b.start()
与正在执行的run
方法之间存在轻微延迟b
上的锁并进入synchronized
块b
(释放锁)run
开始执行时,监视器可用(或将很快提供),以便它可以进入synchronized
块b
它可以停止等待但是,根据线程调度,run
首先执行是不可能的,在这种情况下,主线程可以在b.wait()
上永远等待。例如,如果您通过在Thread.sleep(100)
之后插入一个小的b.start()
来帮助实现这种情况,那么您应该观察到这种情况。
底线:它是一个可能遇到活动问题的臭代码(因为锁可用,它本身并不是死锁)。
答案 1 :(得分:4)
取决于。
来自wait方法的文档 -
使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。换句话说,此方法的行为就像它只是执行call wait(0)一样。
当前线程必须拥有此对象的监视器。线程发布 此监视器的所有权,并等待另一个线程通知 在这个对象的监视器上等待通过a唤醒的线程 调用notify方法或notifyAll方法。线程然后 等到它可以重新获得监视器的所有权并恢复 执行。
所以,如果你考虑这两种情况 -
ThreadA
首先获取对象b
的锁定,它将等待,从而导致释放锁定,这将导致ThreadB
继续其工作。ThreadB
首先获得锁定,那么它将继续它的工作,释放锁定,然后ThreadA
将启动。接下来,ThreadA
将等待对象锁b
,这可能导致它永远等待。