前提:notify导致的死锁不是争夺资源引起的死锁
首先我们要知道。在Java中当线程使用了wati 、 notify后,锁就自动升级为总量级锁了,这时会使用操作系统提供的monitor对象。monitor对象内有waitSet和entryList.
其中 waitSet 中的对象,只能由notify或者notifyAll唤醒后才会去争夺锁。
而entryList中的对象,则是有机会就会去尝试获取锁。
notify每次只随机唤醒waitSet内的一个线程
notifyAll 会将waitSet内的所有线程都唤醒
class OutTurn {
private boolean isSub = true;
private int count = 0;
public synchronized void sub() {
try {
while (!isSub) {
this.notify();
System.out.println("b");
this.wait();
}
System.out.println("sub ---- " + count);
isSub = false;
this.notify();
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
public synchronized void main() {
try {
while (isSub) {
this.notify();
System.out.println("a");
this.wait();
}
System.out.println("main ( " + count);
isSub = true;
this.notify();
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
}
class LockDemo {
public static void main(String[] args) {
final OutTurn ot = new OutTurn();
for (int j = 0; j < 100; j++) {
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
ot.sub();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
ot.main();
}
}
}).start();
}
}
}
在上面代码的场景中,我们假设sub为生产者main为消费者
当waitSet中有大量的 sub 和 main 时, 此时如果有一个生产者获取了锁对象 之后发现不需要生产了,之后释放锁然后notify此时就很可能会再次唤醒生产者。这就是notify导致死锁的原因了。