Java wait/notify/notifyAll知识整理

这几天抽空整理了一下java中wait/notify/notifyall的知识点,如果有写的不好的地方,欢迎各位留言

1、wait()/notify()/notifyAll() 方法在使用时, 必须使用同一个对象的锁。

2、wait()方法执行时,会释放锁,同时线程挂起

3、notify()/notifyAll()方法执行的时候,并不会立刻唤醒,因为(notify()/notifyAll() 并不释放锁),而是退出同步块之后,才唤醒

4、notify()默认唤醒策略是:先进入wait的线程先被唤醒 (可以自己设置策略)

5、notifyAll()默认唤醒策略是:采用LIFO策略 (可以自己设置策略)

6、简单介绍ObjectMonitor+ObjectWaiter (这里只是单纯介绍一下 这两个类是干啥的,如需深入探求则需要查询相关资料和jdk源码)

6.1 ObjectMonitor介绍:

6.1.1 在Hotspot虚拟机中,monitor采用ObjectMonitor实现

6.1.2 每个线程都有两个ObjectMonitor对象列表,分别为free和used列表,如果当前free列表为空,线程将向global中 listLock 请求分配ObjectMonitor

6.1.3 ObjectMonitor有_WaitSet 和 _EntryList(or _cxq)队列, 用来保存ObjectWaiter列表,_owner表示获得ObjectMonitor对象的线程

(此图来源网络)

_WaitSet:处于wait状态的线程,会被加入到此队列中

_EntryList: 处于等待锁block状态的线程,会被加入到此队列中

6.2 ObjectWaiter介绍

6.2.1 ObjectWaiter是一个环型双向链表结构

6.2.2 ObjectWaiter是通过由当前Thread + TState等数据构造而来的

7、wait()具体做了什么事情?

7.1 由当前Thread包装为ObjectWaiter,此时TState=TS_WAIT

7.2 ObjectWaiter对象放入到ObjectMonitor的_WaitSet 队列中

7.3 释放锁,并让当前线程挂起 (使用park/unpark,会释放CPU)

8、notify()具体做了什么事情?

8.1 如果当前_waitSet队列为空,即表示没有线程在等待,那么直接返回

8.2 从_waitSet队列中 取出第一个ObjectWaiter节点

8.3 根据Policy的不同,将这个ObjectWaiter放入到_EntryList队列中

或通过Atomic::cmpxchg_ptr 指令进行自旋操作cxq

8.3.1

Policy==0: 放入_EntryList队列的排头位置

Policy==1: 放入_EntryList队列的末尾位置

Policy==2: _EntryList队列为空就放入_EntryList,否则放入_cxq队列的排头位置

Policy==3: 放入_cxq队列的末尾位置

Policy==其他值: 立刻唤醒ObjectWaiter对应的线程

8.4 当notify退出同步块之后,根据QMode的不同,将ObjectWaiter对象从_EntryList队列或_cxq中取出,在竞争锁

8.4.1

QMode=2,并且_cxq非空:取_cxq队列排头位置的ObjectWaiter对象

QMode=3,并且_cxq非空:把_cxq队列首元素放入到_EntryList队列的尾部

QMode=4,并且_cxq非空:取_cxq队列首元素放入到_EntryList队列的头部

参考:

https://cloud.tencent.com/developer/article/1013062

https://www.jianshu.com/p/f4454164c017

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180130G0CU9200?refer=cp_1026

扫码关注云+社区