ObjectMonitor,ObjectWaiter 实现wait(),notify()
0、java对象锁监视器
在JVM的规范中,有这么一些话:
“在JVM中,每个对象和类在逻辑上都是和一个监视器相关联的”
“为了实现监视器的排他性监视能力,JVM为每一个对象和类都关联一个锁”
“锁住了一个对象,就是获得对象相关联的监视器”
监视器好比一做建筑,它有一个很特别的房间,房间里有一些数据,而且在同一时间只能被一个线程占据,
进入这个建筑叫做"进入监视器"
进入建筑中的那个特别的房间叫做"获得监视器"
占据房间叫做"持有监视器"
离开房间叫做"释放监视器"
离开建筑叫做"退出监视器".
而一个锁就像一种任何时候只允许一个线程拥有的特权.
一个线程可以允许多次对同一对象上锁.对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁,没被锁的对象的计数器是0,线程每加锁一次,计数器就加1,每释放一次,计数器就减1.当计数器跳到0的时候,锁就被完全释放了.
java虚拟机中的一个线程在它到达监视区域开始处的时候请求一个锁.JAVA程序中每一个监视区域都和一个对象引用相关联
监视器:monitor
锁:lock(JVM里只有一种独占方式的lock)
进入监视器:monitorenter
离开/释放监视器:monitorexit
(monitorenter和monitorexit是JVM的指令)
拥有者:owner
在JVM里,monitor就是实现lock的方式。
monitorenter就是获得某个对象的lock(owner是当前线程)
monitorexit就是释放某个对象的lock
在oracle JVM 1.6 里面实现的object的wait 和notify方法是在synchronizer.cpp里实现。
先介绍2个对象:
一. ObjectMonitor 对象 主要用来监视创立的Object
在synchronizer.cpp 里定义了,ObjectMonitor 的对象,我们来看ObjectMonitor的对象的结构体
ObjectMonitor::ObjectMonitor() {
_header = NULL;
_count = ;
_waiters = ,
_recursions = ;
_object = NULL;
_owner = NULL;
_WaitSet = NULL;
_WaitSetLock = ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ;
_SpinFreq = ;
_SpinClock = ;
OwnerIsThread = ;
}
每个object的对象里 markOop->monitor() 里可以保存ObjectMonitor的对象。
建立ObjectMonitor的算法:
如果不存在,可以向Thread 的ObjectMonitor 的对象列表中Allocate free objectMonitor 对象。
每个线程都有ObjectMonitor 的free和used的objectMonitor对象列表,如果没有free objectMonitor对象列表,将向global 中ListLock Allocate为了提高效率。
二. ObjectWaiter 对象
ObjectWaiter 对象
class ObjectWaiter : public StackObj {
public:
enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
enum Sorted { PREPEND, APPEND, SORTED } ;
ObjectWaiter * volatile _next;
ObjectWaiter * volatile _prev;
Thread* _thread;
ParkEvent * _event;
volatile int _notified ;
volatile TStates TState ;
Sorted _Sorted ; // List placement disposition
bool _active ; // Contention monitoring is enabled
public:
ObjectWaiter(Thread* thread) {
_next = NULL;
_prev = NULL;
_notified = ;
TState = TS_RUN ;
_thread = thread;
_event = thread->_ParkEvent ;
_active = false;
assert (_event != NULL, "invariant") ;
}
void wait_reenter_begin(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
_active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
}
void wait_reenter_end(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
}
};
ObjectWaiter 对象里存放thread(线程对象) 和 ParkEvent(线程的unpark), 每一个等待锁的线程都会有一个ObjectWaiter对象.
而objectwaiter是个双向链表结构的对象。
我们可以看到在ObjectMonitor对象里有2个队列成员_WaitSet 和 _EntryList 存放的就是ObjectWaiter
_WaitSet:
主要存放所有wait的线程的对象,也就是说如果有线程处于wait状态,将被挂入这个队列
_EntryList:
所有在等待获取锁的线程的对象,也就是说如果有线程处于等待获取锁的状态的时候,将被挂入这个队列。
三、Wait 方法实现:
ObjectSynchronizer::wait方法
通过object的对象中找到ObjectMonitor对象
调用方法
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)
通过ObjectMonitor::AddWaiter调用把新建立的ObjectWaiter对象放入到 _WaitSet 的队列的末尾中
然后在ObjectMonitor::exit释放锁,接着 thread_ParkEvent->park 也就是wait
四、Notify方法的实现:
ObjectSynchronizer::notify方法
调用ObjectSynchronizer::inflate
object的对象中找到ObjectMonitor对象
然后调用方法ObjectMonitor::notify
调用ObjectMonitor::DequeueWaiter 摘除第一个ObjectWaiter对象从_WaitSet 的队列中
并把这个ObjectWaiter对象放入_EntryList中,_EntryList 存放的是ObjectWaiter的对象列表,列表的大小就是那些所有在等待这个对象锁的线程数。
注意这里并没有调用ObjectMonitor::exit释放锁
NotifyALL和Notify 的区别就是
通过遍历调用ObjectMonitor::DequeueWaiter,把所有的_WaitSet的队列中的ObjectWaiter对象放入到_EntryList中
关于放入到_EntryList的策略大概有4中Policy,其中还涉及到一个_cxq的队列,先不具体介绍了
notify, 和notifyAll 都没有释放对象的锁,而是在Synchronizer同步块结束的时候释放
如何释放锁
调用ObjectMonitor::exit
从_EntryList里找到一个ObjectWaiter,因为ObjectWaiter里有线程的_event ParkEvent,调用unpark() 通知ObjectWaite里的线程运行(拿到锁),具体实现在ObjectMonitor::ExitEpilog方法里
Reference
http://bbs.csdn.net/topics/80052746
ObjectMonitor,ObjectWaiter 实现wait(),notify()的更多相关文章
- JVM源码分析之Object.wait/notify实现(转载)
最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提供一个稳定的基础,Object作为java中所有对象的基类,其存在的价值不言而喻,其中wait和notify方法的实现多线程协作提供了保证. ...
- Java多线程(六):wait(),notify()和notifyAll()
wait(),notify()和notifyAll()介绍 1.wait() 使当前线程等待,直到另一个线程调用notify(),notifyAll()或者中断,当前线程调用wait()之前必须持有锁 ...
- Java精通并发-透过openjdk源码分析wait与notify方法的本地实现
上一次https://www.cnblogs.com/webor2006/p/11442551.html中通过openjdk从c++的底层来审视了ObjectMonitor的底层实现,这次继续来探究底 ...
- 通过openjdk源码分析ObjectMonitor底层实现
通过openjdk源码分析ObjectMonitor底层实现 Hotspot JDK只是部分开源,将底层的调用C++的native方法的具体实现屏蔽了,而openjdk则将这部分也开源了,接下来我们通 ...
- JVM源码分析之Object.wait/notify实现
“365篇原创计划”第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Object.wait/notify实现 最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提 ...
- 话说 wait、notify 、 notifyAll
一.前言 说起java的线程之间的通信,难免会想起它,他就是 wait .notify.notifyAll 他们三个都是Object类的方法, 受到 final 和 native 加持 ,也就造就了他 ...
- jvm源码解读--17 Java的wait()、notify()学习
write and debug by 张艳涛 wait()和notify()的通常用法 A线程取得锁,执行wait(),释放锁; B线程取得锁,完成业务后执行notify(),再释放锁; B线程释放锁 ...
- 面试突击41:notify是随机唤醒吗?
做 Java 开发的小伙伴,对 wait 方法和 notify 方法应该都比较熟悉,这两个方法在线程通讯中使用的频率非常高,但对于 notify 方法的唤醒顺序,有很多小伙伴的理解都是错误的,有很多人 ...
- Thread Object wait() notify()基本
package com.thread.test.thread; import java.util.ArrayDeque; import java.util.Queue; import java.uti ...
随机推荐
- 20个C语言中常用宏定义总结
01: 防止一个头文件被重复包含 #ifndef COMDEF_H#define COMDEF_H//头文件内容#endif 02: 重新定义一些类型防止由于各种平台和编译器的不同,而产生的类型字节数 ...
- HLA高级汇编语言基础
HLA高级汇编语言环境的搭建与设置 我的操作系统:WINDOWS7 需要下载的东西:MASM32:http://www.masm32.com/masmdl.htm HLA:http://webste ...
- MySQL常用SQL/函数汇总(持续更新)
自动生成ROWNUN SELECT (@rowNO := @rowNo+1) AS rowno,a.uuid FROM (SELECT * FROM h_log_proc) a,(SELECT @ro ...
- 四 mybatis开发dao的方法
mybatis开发dao的方法 1.1 SqlSession使用范围 1.1.1 SqlSessionFactoryBuilder //以流的方式读取总的配置文件 Reader rea ...
- [dpdk] 读官方文档(3)
续前节, 测试小程序 1. 想编译测试程序首先需要设置两个环境变量,为什么呢,因为测试程序的Makefile里用了... rpm装了打包好的devel包,这个rpm也会自带这两个环境变量.就是说写第三 ...
- 已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。
今天写ASP.NET程序,在网页后台的c#代码里写了个事务,事务内部对一张表进行批量插入,对另外一张表进行查询与批量插入. 结果第二张表查询后foreach迭代操作时报错:已禁用对分布式事务管理器(M ...
- Bluetooth SDP介绍
目录 1. 概念 2. 服务记录(Service Record) 3. 服务属性(Service Attribute) 4. 服务类(Service Class) 5. 服务查找 5.1 UUID 5 ...
- nrf51822裸机教程-GPIO
首先看看一下相关的寄存器说明 Out寄存器 输出设置寄存器 每个比特按顺序对应每个引脚,bit0对应的就是 引脚0 该寄存器用来设置 引脚作为输出的时候的 输出电平为高还是低. 与输出设置相关的 还有 ...
- C/C++ 判断主机字节存储序列
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA0oAAADFCAIAAADltpUqAAAgAElEQVR4nOyd65XyvA6FqYASKIEWqI
- ADO.NET连接到数据库(oracle)
本文摘抄于http://www.cnblogs.com/luluping/archive/2009/10/13/1582737.html,如有侵权,请联系博主. OracleConnection 对象 ...