您的位置:首页 > 移动开发 > Objective-C

java.lang之java.lang.Object源码阅读及分析

2017-12-09 22:33 447 查看
Object是java中一切类的基础父类,下面看下Object中主要的函数

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方法释放锁!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息