这三个方法都是Object的方法,它们共同作用实现了java线程的阻塞和切换

先决条件

要想在程序中使用这三个方法,必须先要获得锁,否则会抛 IllegalMonitorStateException

wait()使用

当使用wait()释放锁,阻塞当前线程时,如果使用了条件判断,那么需要使用 while() 包括,这样避免了虚假唤醒
虚假唤醒:当线程没有timeout,或者没有被通知唤醒,也没有被打断时候,它自己wakeup了,这就是虚假唤醒

  1. synchronized(obj){
  2. while (a.isEmpty()) {
  3. obj.wait();
  4. }
  5. }

notify() notfiyAll()

这两个方法的区别就是一个唤醒一个线程,一个唤醒所有等待队列中的线程,这两个方法不会释放锁
当线程被唤醒后,它会从wait set进入到entry set中去,参与下一次的锁竞争

1).Jvm的内部锁对象(synchonized)维护两个集合Entry list 和 Wait Set。
2).未抢占到cpu资源或被唤醒却未抢占到cpu资源(即为抢到锁)的线程会放置在Entry list中。
3).调用wait()方法的线程进入Wait Set。
4).Entry list集合的线程为Blocked状态,Wait Set集合中的线程为Waiting状态。
5).当锁资源被释放时,JVM通知Entry list的某一个线程状态会从blocked变成Runnable状态。
6).当调用notify()方法时,JVM会使得Wait Set中的某一线程被唤醒,从waiting状态编程runnable,调用 notifyAll()时,Wait Set的所有线程都被唤醒,状态从waiting变成runnbale,并移入Entry list中或者自旋等待获取锁。
7)所有runnable状态的线程竞争获取锁,只有一个线程获取到锁,其他线程竞争失败,继续放到entry set中阻塞。

我们应该尽量使用notifyAll()的原因就是,notify()非常容易导致死锁。