JVM 源码分析14 Object.wait/notify

Object作为java中所有对象的基类,其存在的价值不言而喻,其中wait和notify方法的实现多线程协作提供了保证。

前提:由同一个lock对象调用wait、notify方法。
1、当线程A执行wait方法时,该线程会被挂起;
2、当线程B执行notify方法时,会唤醒一个被挂起的线程A;

lock对象、线程A和线程B三者是一种什么关系?根据上面的结论,可以想象一个场景:
1、lock对象维护了一个等待队列list;
2、线程A中执行lock的wait方法,把线程A保存到list中;
3、线程B中执行lock的notify方法,从等待队列中取出线程A继续执行;

1、进入wait/notify方法之前,为什么要获取synchronized锁?
2、线程A获取了synchronized锁,执行wait方法并挂起,线程B又如何再次获取锁

获取对象monitor,表示线程执行lock.wait()方法时,必须持有该lock对象的monitor,如果wait方法在synchronized代码中执行,该线程很显然已经持有了monitor。

代码执行过程分析

1、在多核环境下,线程A和B有可能同时执行monitorenter指令,并获取lock对象关联的monitor,只有一个线程可以和monitor建立关联,假设线程A执行加锁成功;
2、线程B竞争加锁失败,进入等待队列进行等待;
3、线程A继续执行,当执行到wait方法时,会发生什么?wait接口注释:

This method causes the current thread to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object.

wait方法会将当前线程放入wait set,等待被唤醒,并放弃lock对象上的所有同步声明,意味着线程A释放了锁,线程B可以重新执行加锁操作,不过又有一个疑问:在线程A的wait方法释放锁,到线程B获取锁,这期间发生了什么?线程B是如何知道线程A已经释放了锁?好迷茫....


4、线程B执行加锁操作成功,对于notify方法,JDK注释:notify方法会选择wait set中任意一个线程进行唤醒;

notifyAll方法的注释:notifyAll方法会唤醒monitor的wait set中所有线程。

5、执行完notify方法,并不会立马唤醒等待线程,在notify方法后面加一段sleep代码就可以看到效果,如果线程B执行完notify方法之后sleep 5s,在这段时间内,线程B依旧持有monitor,线程A只能继续等待;

那么wait set的线程什么时候会被唤醒?

**_WaitSet ** :处于wait状态的线程,会被加入到wait set;
_EntryList:处于等待锁block状态的线程,会被加入到entry set;

3、通过ObjectMonitor::exit方法释放当前的ObjectMonitor对象,这样其它竞争线程就可以获取该ObjectMonitor对象。

猜你喜欢

转载自blog.csdn.net/kuaipao19950507/article/details/106295346