java.lang之java.lang.Object源码阅读及分析
2017-12-09 22:33
447 查看
Object是java中一切类的基础父类,下面看下Object中主要的函数
1,wait函数
下面看下在jvm中,wait是如何实现的。
那这个object monitor究竟是如何产生的呢,又是存放在何处?在回答这个之前,就不得不了解一下java对象头部mark_word在内存中的布局(图片来自网上)
有了这个图作为基础,下面对照着代码,看下object monitor是如何产生的。
mark->monitor(),获取对象监视器,实现方式为(ObjectMonitor*) (value() ^ monitor_value),头部的mark_word值与monitor_vaue进行异或操作,正好是取的图中前30位二进制数.嚯嚯,这下清楚了,上图中所谓的指向互斥量的指针原来就是ObjectMonitor的地址,原来所谓的对象监视器就存储在对象的头部mark_word中!!!
上面是对象已有监视器的情况,接着往下看
首先看下omAlloc(Self)是如何分配Object monitor的,代码就不贴了,有点长,下面说下分配的过程
a,如果当前线程中omFreeList不为空,分配当前线程omFreeList的头结点。否则进入b
b,如果全局的gFreelist不为空,从gFreelist中分配,否则进入c
c,new一个128大小的ObjectMonitor数组,第0个元素保留, 建立freelist链表,并与gFreeList连通,gFreeList指向新建立的链表.进入下一次循环
d,下一次循环进来时,尝试从gFreeList中分配,这时会将gFreeList链表放入到当前线程的omFreeList中,进入下一次循环
e,循环进来时,这次是这正的分配到ObjectMonitor了,如果此时ObjectMonitor正在被使用,则被加入到当前线程的omInUseList链表中
至此,分配ObjectMonitor结束! 接下来就是执行ObjectMonitor的wait方法了
a,首先能够调用wait方法,说明已经持有锁(或者说进入了synchronized代码块),而wait依赖于对象监视器objectmonitor的实现,所以首先得要获取这个monitor
b,monitor的指针存放在对象的头部,如果对象的头部没有,首先尝试从当前线程维护的omFreelist链表中分配,如果没有,从全局的gFreelist中分配,如果还没分配到,通过new的方式分配一个128大小的ObjectMonitor数组,放入到当前线程的omFreelist,以及全局的gFreelist,同时设置必要的信息
c,monitor分配好以后,进入wait,首先将当前线程封装成一个ObjectWaiter放入到objectMonitor的waitset队列中,然后退出对象监视器,挂起当前线程!
2,notify函数
看下其在jvm中的实现:
void ObjectMonitor::notify(TRAPS) {
.......
ObjectWaiter * iterator = DequeueWaiter() ;//选择头结点,有随机性,不一定是FIFO
if (i
a77c
terator != NULL) {
........
iterator->_notified = 1 ;//设置notify为1
Thread * Self = THREAD;
iterator->_notifier_tid = Self->osthread()->thread_id();
ObjectWaiter * List = _EntryList ;//准备进入同步代码块的队列
.........
if (Policy == 2) { // prepend to cxq 默认为2,将唤醒的ObjectWaiter放入到cxq队列最前面
// prepend to cxq
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
}
}
if (Policy < 4) {
iterator->wait_reenter_begin(this);//设置线程状态为正在重新获取锁(进入同步代码块)
}
........
}
}从上可以看出,notify时只是把notify标志职位1,当前线程加入到enter(synchronized)队列中,准备重新获取锁。既没有unpark挂起的线程,也没有调用ObjectMonitor::exit方法释放锁!!!!!
1,wait函数
public final void wait() throws InterruptedException { wait(0); }该函数有段注释需要特别注意
* The current thread must own this object's monitor. The thread * releases ownership of this monitor and waits until another thread * notifies threads waiting on this object's monitor to wake up * either through a call to the {@code notify} method or the * {@code notifyAll} method. The thread then waits until it can * re-obtain ownership of the monitor and resumes execution. * This method should only be called by a thread that is the owner * of this object's monitor.wait方法的调用需要在当前线程持有该对象的监视器,意思就是当前线程竞争到了锁,才可以调用wait方法,通常与synchronized关键字一起用。
下面看下在jvm中,wait是如何实现的。
void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { //省略部分代码 ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());//获取对象监视器 DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis); monitor->wait(millis, true, THREAD);//调用对象监视器wait /* This dummy call is in place to get around dtrace bug 6254741. Once that's fixed we can uncomment the following line and remove the call */ // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD); dtrace_waited_probe(monitor, obj, THREAD); }
ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());这句代码就是获取上文中所说的对象监视器,ObjectMonitor的结构如下:
// initialize the monitor, exception the semaphore, all other fields // are simple integers or pointers ObjectMonitor() { _header = NULL;// displaced object header word - mark _count = 0;// reference count to prevent reclaimation/deflation // at stop-the-world time. See deflate_idle_monitors(). // _count is approximately |_WaitSet| + |_EntryList| _waiters = 0,// number of waiting threads _recursions = 0;// recursion count, 0 for first entry _object = NULL;// backward object pointer - strong root _owner = NULL;// pointer to owning thread OR BasicLock _WaitSet = NULL;// LL of threads wait()ing on the monitor _WaitSetLock = 0 ;// protects Wait Queue - simple spinlock _Responsible = NULL ; _succ = NULL ;// Heir presumptive thread - used for futile wakeup throttling _cxq = NULL ;// LL of recently-arrived threads blocked on entry. // The list is actually composed of WaitNodes, acting // as proxies for Threads. FreeNext = NULL ;// Free list linkage _EntryList = NULL ;// Threads blocked on entry or reentry. _SpinFreq = 0 ;// Spin 1-out-of-N attempts: success rate _SpinClock = 0 ; OwnerIsThread = 0 ;// _owner is (Thread *) vs SP/BasicLock _previous_owner_tid = 0;// thread id of the previous owner of the monitor }
那这个object monitor究竟是如何产生的呢,又是存放在何处?在回答这个之前,就不得不了解一下java对象头部mark_word在内存中的布局(图片来自网上)
有了这个图作为基础,下面对照着代码,看下object monitor是如何产生的。
const markOop mark = object->mark();//获取对象的头部mark_word,如上图表示 if (mark->has_monitor()) {//当前对象已有monitor ObjectMonitor * inf = mark->monitor() ; assert (inf->header()->is_neutral(), "invariant"); assert (inf->object() == object, "invariant") ; assert (ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid"); return inf ; }mark->has_monitor(),判断当前对象是否已经有了监视器,其判断的方式为((value() & monitor_value) != 0),value表示头部的mark_word值,monitor_value=2,用二进制表示就是10,正好对应上图中重量级锁的锁标志位,其实就是判断对象是否被重量级标记,再往下看,
mark->monitor(),获取对象监视器,实现方式为(ObjectMonitor*) (value() ^ monitor_value),头部的mark_word值与monitor_vaue进行异或操作,正好是取的图中前30位二进制数.嚯嚯,这下清楚了,上图中所谓的指向互斥量的指针原来就是ObjectMonitor的地址,原来所谓的对象监视器就存储在对象的头部mark_word中!!!
上面是对象已有监视器的情况,接着往下看
if (mark == markOopDesc::INFLATING()) { TEVENT (Inflate: spin while INFLATING) ; ReadStableMark(object) ; continue ; }如果当前的锁正在膨胀中(轻量级锁膨胀为重量级锁),重新获取mark_word,进入下一次循环.这里有个问题,如何判断锁正处在膨胀中呢?
static markOop INFLATING() { return (markOop) 0; } // inflate-in-progress再次对照上图,锁标志位00表示为轻量级锁标记,但是指向栈中锁记录的指针为NULL,哦,原来mark_word值为0x00000000时表示锁正在膨胀中,再往下看
if (mark->has_locker()) {//被轻量级锁标记 ObjectMonitor * m = omAlloc (Self) ;//从当前线程中分配ObjectMonitor m->Recycle();//置回初始状态 m->_Responsible = NULL ; m->OwnerIsThread = 0 ; m->_recursions = 0 ; m->_SpinDuration = ObjectMonitor::Knob_SpinLimit ; // Consider: maintain by type/class //cas方式尝试膨胀,如果失败,进入下一次循环 markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ; if (cmp != mark) { omRelease (Self, m, true) ; continue ; // Interference -- just retry } m->set_header(dmw) ; m->set_owner(mark->locker()); m->set_object(object); object->release_set_mark(markOopDesc::encode(m));//将monitor地址set到对象头部 }
首先看下omAlloc(Self)是如何分配Object monitor的,代码就不贴了,有点长,下面说下分配的过程
a,如果当前线程中omFreeList不为空,分配当前线程omFreeList的头结点。否则进入b
b,如果全局的gFreelist不为空,从gFreelist中分配,否则进入c
c,new一个128大小的ObjectMonitor数组,第0个元素保留, 建立freelist链表,并与gFreeList连通,gFreeList指向新建立的链表.进入下一次循环
d,下一次循环进来时,尝试从gFreeList中分配,这时会将gFreeList链表放入到当前线程的omFreeList中,进入下一次循环
e,循环进来时,这次是这正的分配到ObjectMonitor了,如果此时ObjectMonitor正在被使用,则被加入到当前线程的omInUseList链表中
至此,分配ObjectMonitor结束! 接下来就是执行ObjectMonitor的wait方法了
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { //省略部分代码 jt->set_current_waiting_monitor(this);//设置当前正在waiting的监视器 ObjectWaiter node(Self);//将当前线程封装成一个ObjectWaiter Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ; AddWaiter (&node) ;//添加到ObjectMonitor的等待队列中_Waitset Thread::SpinRelease (&_WaitSetLock) ; exit (true, Self) ; //退出对象监视器,即将ObjectMonitor中的_owner置为NULL int ret = OS_OK ; int WasNotified = 0 ; { // State transition wrappers OSThread* osthread = Self->osthread(); OSThreadWaitState osts(osthread, true); { ....... if (node._notified == 0) {//如果此时没有被唤醒 if (millis <= 0) { Self->_ParkEvent->park () ;//挂起当前线程,windows下是调用WINAPI函数waitforsingleobject } else { ret = Self->_ParkEvent->park (millis) ; } } ....... } ..... }综上,我们来总结下Object.wait()实现原理:
a,首先能够调用wait方法,说明已经持有锁(或者说进入了synchronized代码块),而wait依赖于对象监视器objectmonitor的实现,所以首先得要获取这个monitor
b,monitor的指针存放在对象的头部,如果对象的头部没有,首先尝试从当前线程维护的omFreelist链表中分配,如果没有,从全局的gFreelist中分配,如果还没分配到,通过new的方式分配一个128大小的ObjectMonitor数组,放入到当前线程的omFreelist,以及全局的gFreelist,同时设置必要的信息
c,monitor分配好以后,进入wait,首先将当前线程封装成一个ObjectWaiter放入到objectMonitor的waitset队列中,然后退出对象监视器,挂起当前线程!
2,notify函数
看下其在jvm中的实现:
void ObjectMonitor::notify(TRAPS) {
.......
ObjectWaiter * iterator = DequeueWaiter() ;//选择头结点,有随机性,不一定是FIFO
if (i
a77c
terator != NULL) {
........
iterator->_notified = 1 ;//设置notify为1
Thread * Self = THREAD;
iterator->_notifier_tid = Self->osthread()->thread_id();
ObjectWaiter * List = _EntryList ;//准备进入同步代码块的队列
.........
if (Policy == 2) { // prepend to cxq 默认为2,将唤醒的ObjectWaiter放入到cxq队列最前面
// prepend to cxq
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
}
}
if (Policy < 4) {
iterator->wait_reenter_begin(this);//设置线程状态为正在重新获取锁(进入同步代码块)
}
........
}
}从上可以看出,notify时只是把notify标志职位1,当前线程加入到enter(synchronized)队列中,准备重新获取锁。既没有unpark挂起的线程,也没有调用ObjectMonitor::exit方法释放锁!!!!!
相关文章推荐
- java.lang.Object源码阅读笔记
- JDK源码阅读系列(1) java.lang.Object
- java源码阅读之java.lang.Object
- 源码阅读笔记:java.lang.Object
- java.lang之java.lang.String 源码阅读及分析
- java.lang.Integer源码分析
- JDK源码分析:Object.java
- java.lang.Object.clone()分析
- Java源码分析--Object
- Java基础-----基类Object源码分析
- java.lang.Object.clone()分析
- 源码分析 There is no getter for property named '*' in 'class java.lang.String
- 运行mvn命令出现java/lang/NoClassDefFoundError: java/lang/Object错误解决方案及原因分析
- JDK源码阅读——java.lang.Character
- Android源码分析:Java的Media Scanner层(阅读笔记)
- jdk源码阅读之 java.lang.Iterable
- jdk1.8 J.U.C并发源码阅读------AQS之conditionObject内部类分析
- java.lang.String源码分析
- 源码分析 There is no getter for property named '*' in 'class java.lang.String
- JDK源码分析:java.lang.String