目录
- 锁池与等待池
- 执行wait()方法
- 调用notify()/notifyAll()方法
- notify()可能导致死锁
参考知乎高?回答:java中的notify和notifyAll有什么区别?
锁池与等待池
首先要明白锁池和等待池的区别,现在有一个线程A拥有了Obj对象的锁:
锁池:这时候有其他的线程要来竞争这个对象锁,但是线程A在占用这个对象锁,因此其余的线程都在这个Obj对象的锁池中。
等待池:线程A调用了对象Obj的wait()方法,线程A就会释放Obj的对象锁,进入到该对象的等待池中。
执行wait()方法
一个对象调用了wait()方法,则线程会处于该对象的等待池中,等待池中的线程不会去竞争该对象。
调用notify()/notifyAll()方法
但是对象调用了notify()/notifyAll方法之后,就会唤醒等待池中的线程,被唤醒的线程会进入到该对象的锁池中。notify()会唤醒一个线程从等待池到锁池,而notifyAll()会唤醒该对象等待池中的所有对象进入到锁池中,准备竞争这个对象锁。
一般来说,高优先级的线程更容易竞争到这个Obj对象锁,一旦竞争到了,就正常执行synchronized方法,执行完毕之后,其余的线程继续竞争Obj。没有竞争成功的线程依旧留在对象的锁池中。
因此,notify()和notifyAll()共同的作用就是将线程从对象的等待池转移到对象的锁池,区别在于前者是唤醒一个线程,后者是唤醒所有等待线程。
notify()可能导致死锁
以上的内容也可以用来解释为什么notify()可能会导致死锁,但是notifyAll()并不会:
假如说这个时候Obj的等待池中,已经有线程A, B, C了,此时线程D持有Obj的锁,调用Obj的wait()方法,此时线程D也进入到了等待池中,Obj锁池中的线程得到Obj之后,就再也没有执行过notify()方法,则导致等待池中的线程一直都处于等待状态,永远不会被唤醒进入到该对象的锁池,因此解决的方法就是执行notifyAll(),唤醒所有的等待线程,防止出现死锁情况。