可以。
-----------------------------------------
(⊙o⊙)…, 写了这么多只有3赞。怒而直接将本文发布在我的专栏:HotSpot VM重量级锁降级机制的实现原理 。
-----------------------------------------
HotSpot VM内置锁的同步机制简述:
HotSpot VM采用三中不同的方式实现了对象监视器——Object Monitor,并且可以在这三种实现方式中自动切换。偏向锁通过在Java对象的对象头markOop中install一个JavaThread指针的方式实现了这个Java对象对此Java线程的偏向,并且只有该偏向线程能够锁定Lock该对象。但是只要有第二个Java线程企图锁定这个已被偏向的对象时,偏向锁就不再满足这种情况了,然后呢JVM就将Biased Locking切换成了Basic Locking(基本对象锁)。Basic Locking使用CAS操作确保多个Java线程在此对象锁上互斥执行。如果CAS由于竞争而失败(第二个Java线程试图锁定一个正在被其他Java线程持有的对象),这时基本对象锁因为不再满足需要从而JVM会切换到膨胀锁 - ObjectMonitor。不像偏向锁和基本对象锁的实现,重量级锁的实现需要在Native的Heap空间中分配内存,然后指向该空间的内存指针会被装载到Java对象中去。这个过程我们称之为锁膨胀。
降级的目的和过程:
因为BasicLocking的实现优先于重量级锁的使用,JVM会尝试在SWT的停顿中对处于“空闲(idle)”状态的重量级锁进行降级(deflate)。这个降级过程是如何实现的呢?我们知道在STW时,所有的Java线程都会暂停在“安全点(SafePoint)”,此时VMThread通过对所有Monitor的遍历,或者通过对所有依赖于MonitorInUseLists值的当前正在“使用”中的Monitor子序列进行遍历,从而得到哪些未被使用的“Monitor”作为降级对象。
可以降级的Monitor对象:
重量级锁的降级发生于STW阶段,降级对象就是那些仅仅能被VMThread访问而没有其他JavaThread访问的对象。
HotSpot VM中的实现:
上述降级过程在HotSpot VM中的实现,可以参考:
void ObjectSynchronizer::deflate_idle_monitors() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
int nInuse = 0 ; // currently associated with objects int nInCirculation = 0 ; // extant int nScavenged = 0 ; // reclaimed bool deflated = false;
ObjectMonitor * FreeHead = NULL ; // Local SLL of scavenged monitors ObjectMonitor * FreeTail = NULL ;
TEVENT (deflate_idle_monitors) ;
// Prevent omFlush from changing mids in Thread dtor's during deflation // And in case the vm thread is acquiring a lock during a safepoint // See e.g. 6320749 Thread::muxAcquire (&ListLock, "scavenge - return") ;
if (MonitorInUseLists) {
int inUse = 0;
for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) {
nInCirculation+= cur->omInUseCount;
int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail);
cur->omInUseCount-= deflatedcount;
// verifyInUse(cur); nScavenged += deflatedcount;
nInuse += cur->omInUseCount;
}
// For moribund threads, scan gOmInUseList if (gOmInUseList) {
nInCirculation += gOmInUseCount;
int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail);
gOmInUseCount-= deflatedcount;
nScavenged += deflatedcount;
nInuse += gOmInUseCount;
}
} else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
// Iterate over all extant monitors - Scavenge all idle monitors. assert(block->object() == CHAINMARKER, "must be a block header");
nInCirculation += _BLOCKSIZE ;
for (int i = 1 ; i < _BLOCKSIZE; i++) {
ObjectMonitor* mid = &block[i];
oop obj = (oop) mid->object();
if (obj == NULL) {
// The monitor is not associated with an object. // The monitor should either be a thread-specific private // free list or the global free list. // obj == NULL IMPLIES mid->is_busy() == 0 guarantee (!mid->is_busy(), "invariant") ;
continue ;
}
deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail);
if (deflated) {
mid->FreeNext = NULL ;
nScavenged ++ ;
} else {
nInuse ++;
}
}
}
MonitorFreeCount += nScavenged;
// Consider: audit gFreeList to ensure that MonitorFreeCount and list agree.
if (ObjectMonitor::Knob_Verbose) {
::printf ("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n",
nInCirculation, nInuse, nScavenged, ForceMonitorScavenge,
MonitorPopulation, MonitorFreeCount) ;
::fflush(stdout) ;
}
ForceMonitorScavenge = 0; // Reset
// Move the scavenged monitors back to the global free list. if (FreeHead != NULL) {
guarantee (FreeTail != NULL && nScavenged > 0, "invariant") ;
assert (FreeTail->FreeNext == NULL, "invariant") ;
// constant-time list splice - prepend scavenged segment to gFreeList FreeTail->FreeNext = gFreeList ;
gFreeList = FreeHead ;
}
Thread::muxRelease (&ListLock) ;
if (ObjectMonitor::_sync_Deflations != NULL) ObjectMonitor::_sync_Deflations->inc(nScavenged) ;
if (ObjectMonitor::_sync_MonExtant != NULL) ObjectMonitor::_sync_MonExtant ->set_value(nInCirculation);
// TODO: Add objectMonitor leak detection. // Audit/inventory the objectMonitors -- make sure they're all accounted for. GVars.stwRandom = os::random() ;
GVars.stwCycle ++ ;
}
补充说明:JEP - Concurrent Monitor Deflation,旨在通过并发手段解决重量级锁降级过程中的效率问题,可以参考:JEP draft: Concurrent Monitor Deflation 。