💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 简介 Java Object对象中的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算法决定 ## Demo ~~~ ublic class WaitNotifyCase { public static void main(String[] args) { final Object lock = new Object(); new Thread(new Runnable() { @Override public void run() { System.out.println("thread A is waiting to get lock"); synchronized (lock) { try { System.out.println("thread A get lock"); TimeUnit.SECONDS.sleep(1); System.out.println("thread A do wait method"); lock.wait(); System.out.println("wait end"); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println("thread B is waiting to get lock"); synchronized (lock) { System.out.println("thread B get lock"); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } lock.notify(); System.out.println("thread B do notify method"); } } }).start(); } } ~~~ ## 进入wait/notify方法之前,为什么要获取synchronized锁 我们知道wait/notify是为了线程间协作而设计的,当我们执行wait的时候让线程挂起,当执行notify的时候唤醒其中一个挂起的线程,**那需要有个地方来保存对象和线程之间的映射关系**(可以想象一个map,key是对象,value是一个线程列表) 当调用这个对象的wait方法时,将当前线程放到这个线程列表里,当调用这个对象的notify方法时从这个线程列表里取出一个来让其继续执行 这样看来是可行的,也比较简单,那现在的问题这种映射关系放到哪里? lock.wait()方法通过调用native方法wait(0)实现,其中接口注释中有这么一句: ``` The current thread must own this object’s monitor. ``` 表示线程执行lock.wait()方法时,必须持有该lock对象的ObjectMonitor(前文已经提及,每个锁对象(这里指已经升级为重量级锁的对象)都有一个ObjectMonitor(对象监视器)。也就是说每个线程获取锁对象都会通过ObjectMonitor) 如果wait方法在synchronized代码中执行,该线程很显然已经持有了monitor。 从而包含了“ 进入wait/notify方法之前,为什么要获取synchronized锁”,synchronized代码块通过javap生成的字节码中包含 *monitorenter 和 monitorexit指令。其中执行monitorenter指令可以获取对象的monitor ## 参考资料 [Java并发编程:Object.wait/notify](https://blog.csdn.net/fei20121106/article/details/83268434)