Hotspot虚拟机的对象头包括两部分信息,第一部分用于储存对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标志,锁指针等,这部分数据在32bit和64bit的虚拟机中大小分别为32bit和64bit,官方称它为"Mark word",考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间中存储尽量多的信息,它会根据对象的状态复用自己的存储空间,详细情况如下图:
对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,如果对象访问定位方式是句柄访问,那么该部分没有,如果是直接访问,该部分保留。句柄访问方式如下图:
直接访问如下图:
通常所说的对象的内置锁,是对象头Mark Word中的重量级锁指针指向的monitor对象,该对象是在HotSpot底层C++语言编写的(openjdk里面看),简单看一下代码:
//结构体如下 ObjectMonitor::ObjectMonitor() { _header = NULL; _count = 0; _waiters = 0, _recursions = 0; //线程的重入次数 _object = NULL; _owner = NULL; //标识拥有该monitor的线程 _WaitSet = NULL; //等待线程组成的双向循环链表,_WaitSet是第一个节点 _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; //多线程竞争锁进入时的单向链表 FreeNext = NULL ; _EntryList = NULL ; //_owner从该双向循环链表中唤���线程结点,_EntryList是第一个节点 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; }ObjectMonitor队列之间的关系转换可以用下图表示:
既然提到了_waitSet和_EntryList(_cxq队列后面会说),那就看一下底层的wait和notify方法
wait方法的实现过程:
总结:通过object获得内置锁(objectMonitor),通过内置锁将Thread封装成OjectWaiter对象,然后addWaiter将它插入以_waitSet为首结点的等待线程链表中去,最后释放锁。
notify方法的底层实现
//1.调用ObjectSynchronizer::notify方法 void ObjectSynchronizer::notify(Handle obj, TRAPS) { /*省略*/ //2.调用ObjectSynchronizer::inflate方法 ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD); } //3.通过inflate方法得到ObjectMonitor对象 ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) { /*省略*/ if (mark->has_monitor()) { ObjectMonitor * inf = mark->monitor() ; assert (inf->header()->is_neutral(), "invariant"); assert (inf->object() == object, "invariant") ; assert (ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is inva;lid"); return inf } /*省略*/ } //4.调用ObjectMonitor的notify方法 void ObjectMonitor::notify(TRAPS) { /*省略*/ //5.调用DequeueWaiter方法移出_waiterSet第一个结点 ObjectWaiter * iterator = DequeueWaiter() ; //6.后面省略是将上面DequeueWaiter尾插入_EntrySet的操作 /**省略*/ }