wait,notify,notifyAll 是定义在Object类的实例方法,用于控制线程状态。
三个方法都必须在synchronized 同步关键字所限定的作用域中调用,否则会报错java.lang.IllegalMonitorStateException ,意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。
- wait 表示持有对象锁的线程A准备释放对象锁权限,释放cpu资源并进入等待。
- notify 表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒某个竞争该对象锁的线程X。线程A synchronized 代码作用域结束后,线程X直接获得对象锁权限,其他竞争线程继续等待(即使线程X同步完毕,释放对象锁,其他竞争线程仍然等待,直至有新的notify ,notifyAll被调用)。
- notifyAll 表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒所有竞争该对象锁的线程,线程A synchronized 代码作用域结束后,jvm通过算法将对象锁权限指派给某个线程X,所有被唤醒的线程不再等待。线程X synchronized 代码作用域结束后,之前所有被唤醒的线程都有可能获得该对象锁权限,这个由JVM算法决定。
wait有三个重载方法,同时必须捕获非运行时异常InterruptedException。
- wait() 进入等待,需要notify ,notifyAll才能唤醒
- wait(long timeout) 进入等待,经过timeout 超时后,若未被唤醒,则自动唤醒
- wait(timeout, nanos) 进入等待,经过timeout 超时后,若未被唤醒,则自动唤醒。相对wait(long timeout) 更加精确时间。
好了,来个通俗比喻来理解。角色分配
线程:买家,N个线程表示N个买家
同步块or同步方法:不同的药单。
对象锁:取药窗口,有且只有一个,每次只服务一个买家
图一,表示买家A完成取药后,医院没有叫醒其他熟睡的买家,没有睡觉的C,E买家争抢后,C获得取药机会
图二,表示了notify(医院叫醒了某个熟睡的买家),跟notifyAll(医院叫醒了所有熟睡的买家)的过程。就是这么简单。