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

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 (iterator != 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方法释放锁!!!!!









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值