标签:repr with swing 对齐 recursion 相等 rac sla mon
锁为何存在:
// Handles the uncommon case in locking, i.e., contention or an inflated lock. JRT_BLOCK_ENTRY(void, SharedRuntime::complete_monitor_locking_C(oopDesc* _obj, BasicLock* lock, JavaThread* thread)) // Disable ObjectSynchronizer::quick_enter() in default config // on AARCH64 and ARM until JDK-8153107 is resolved. if (ARM_ONLY((SyncFlags & 256) != 0 &&) AARCH64_ONLY((SyncFlags & 256) != 0 &&) !SafepointSynchronize::is_synchronizing()) { // Only try quick_enter() if we‘re not trying to reach a safepoint // so that the calling thread reaches the safepoint more quickly. if (ObjectSynchronizer::quick_enter(_obj, thread, lock)) return; } // NO_ASYNC required because an async exception on the state transition destructor // would leave you with the lock held and it would never be released. // The normal monitorenter NullPointerException is thrown without acquiring a lock // and the model is that an exception implies the method failed. JRT_BLOCK_NO_ASYNC oop obj(_obj); if (PrintBiasedLockingStatistics) { Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(THREAD, obj); //在 JVM 启动时,我们可以指定是否开启偏向锁 if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation <strong> //fast_enter 是我们熟悉的完整锁获取路径</strong> ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); } else { //slow_enter 则是绕过偏向锁,直接进入轻量级锁获取逻辑 ObjectSynchronizer::slow_enter(h_obj, lock, CHECK); } assert(!HAS_PENDING_EXCEPTION, "Should have no exception here"); JRT_BLOCK_END JRT_END
synchronizer.cpp(https://hg.openjdk.java.net/jdk/jdk/file/896e80158d35/src/hotspot/share/runtime/synchronizer.cpp),JVM 同步相关的各种基础(不仅仅是 synchronized 的逻辑,包括从本地代码,也就是 JNI,触发的 Monitor 动作,全都可以在里面找到例如(jni_enter/jni_exit)):
// ----------------------------------------------------------------------------- // Fast Monitor Enter/Exit // This the fast monitor enter. The interpreter and compiler use // some assembly copies of this code. Make sure update those code // if the following function is changed. The implementation is // extremely sensitive to race condition. Be careful. void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) { if (UseBiasedLocking) { if (!SafepointSynchronize::is_at_safepoint()) { //biasedLocking定义了偏向锁相关操作,revoke_and_rebias revokeatsafepoint 则定义了当检测到安全点时的处理 BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { return; } } else { assert(!attempt_rebias, "can not rebias toward VM thread"); BiasedLocking::revoke_at_safepoint(obj); } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } //如果获取偏向锁失败,则进入 slow_enter,锁升级 slow_enter(obj, lock, THREAD); } // ----------------------------------------------------------------------------- // Interpreter/Compiler Slow Case // This routine is used to handle interpreter/compiler slow case // We don‘t need to use fast path here, because it must have been // failed in the interpreter/compiler code. void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) { markOop mark = obj->mark(); assert(!mark->has_bias_pattern(), "should not see bias pattern here"); if (mark->is_neutral()) { // Anticipate successful CAS -- the ST of the displaced mark must // be visible <= the ST performed by the CAS. // 将目前的 Mark Word 复制到 Displaced Header 上 lock->set_displaced_header(mark); // 利用 CAS 设置对象的 Mark Wo if (mark == obj()->cas_set_mark((markOop) lock, mark)) { return; } // Fall through to inflate() … // 检查存在竞争 } else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) { assert(lock != mark->locker(), "must not re-lock the same lock"); assert(lock != (BasicLock*)obj->mark(), "don‘t relock with same BasicLock”); // 清除 lock->set_displaced_header(NULL); return; } // The object header will never be displaced to this lock, // so it does not matter what the value is, except that it // must be non-zero to avoid looking like a re-entrant lock, // and must not look locked either. // 重置 Displaced Header lock->set_displaced_header(markOopDesc::unused_mark()); //锁膨胀 ObjectSynchronizer::inflate(THREAD, obj(), inflate_cause_monitor_enter)->enter(THREAD); } // This routine is used to handle interpreter/compiler slow case // We don‘t need to use fast path here, because it must have // failed in the interpreter/compiler code. Simply use the heavy // weight monitor should be ok, unless someone find otherwise. void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) { fast_exit(object, lock, THREAD); } //锁膨胀 ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) { // Inflate mutates the heap ... // Relaxing assertion for bug 6320749. assert (Universe::verify_in_progress() || !SafepointSynchronize::is_at_safepoint(), "invariant") ; for (;;) {//自旋 const markOop mark = object->mark() ; assert (!mark->has_bias_pattern(), "invariant") ; // The mark can be in one of the following states: // * Inflated - just return // * Stack-locked - coerce it to inflated // * INFLATING - busy wait for conversion to complete // * Neutral - aggressively inflate the object. // * BIASED - Illegal. We should never see this // CASE: inflated已膨胀,即重量级锁 if (mark->has_monitor()) {//判断当前是否为重量级锁 ObjectMonitor * inf = mark->monitor() ;//获取指向ObjectMonitor的指针 assert (inf->header()->is_neutral(), "invariant"); assert (inf->object() == object, "invariant") ; assert (ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid"); return inf ; } // CASE: inflation in progress - inflating over a stack-lock.膨胀等待(其他线程正在从轻量级锁转为膨胀锁) // Some other thread is converting from stack-locked to inflated. // Only that thread can complete inflation -- other threads must wait. // The INFLATING value is transient. // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. // We could always eliminate polling by parking the thread on some auxiliary list. if (mark == markOopDesc::INFLATING()) { TEVENT (Inflate: spin while INFLATING) ; ReadStableMark(object) ; continue ; } // CASE: stack-locked栈锁(轻量级锁) // Could be stack-locked either by this thread or by some other thread. // // Note that we allocate the objectmonitor speculatively, _before_ attempting // to install INFLATING into the mark word. We originally installed INFLATING, // allocated the objectmonitor, and then finally STed the address of the // objectmonitor into the mark. This was correct, but artificially lengthened // the interval in which INFLATED appeared in the mark, thus increasing // the odds of inflation contention. // // We now use per-thread private objectmonitor free lists. // These list are reprovisioned from the global free list outside the // critical INFLATING...ST interval. A thread can transfer // multiple objectmonitors en-mass from the global free list to its local free list. // This reduces coherency traffic and lock contention on the global free list. // Using such local free lists, it doesn‘t matter if the omAlloc() call appears // before or after the CAS(INFLATING) operation. // See the comments in omAlloc(). if (mark->has_locker()) { ObjectMonitor * m = omAlloc (Self) ;//获取一个可用的ObjectMonitor // Optimistically prepare the objectmonitor - anticipate successful CAS // We do this before the CAS in order to minimize the length of time // in which INFLATING appears in the mark. m->Recycle(); m->_Responsible = NULL ; m->OwnerIsThread = 0 ; m->_recursions = 0 ; m->_SpinDuration = ObjectMonitor::Knob_SpinLimit ; // Consider: maintain by type/class markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ; if (cmp != mark) {//CAS失败//CAS失败,说明冲突了,自旋等待//CAS失败,说明冲突了,自旋等待//CAS失败,说明冲突了,自旋等待 omRelease (Self, m, true) ;//释放监视器锁 continue ; // Interference -- just retry } // We‘ve successfully installed INFLATING (0) into the mark-word. // This is the only case where 0 will appear in a mark-work. // Only the singular thread that successfully swings the mark-word // to 0 can perform (or more precisely, complete) inflation. // // Why do we CAS a 0 into the mark-word instead of just CASing the // mark-word from the stack-locked value directly to the new inflated state? // Consider what happens when a thread unlocks a stack-locked object. // It attempts to use CAS to swing the displaced header value from the // on-stack basiclock back into the object header. Recall also that the // header value (hashcode, etc) can reside in (a) the object header, or // (b) a displaced header associated with the stack-lock, or (c) a displaced // header in an objectMonitor. The inflate() routine must copy the header // value from the basiclock on the owner‘s stack to the objectMonitor, all // the while preserving the hashCode stability invariants. If the owner // decides to release the lock while the value is 0, the unlock will fail // and control will eventually pass from slow_exit() to inflate. The owner // will then spin, waiting for the 0 value to disappear. Put another way, // the 0 causes the owner to stall if the owner happens to try to // drop the lock (restoring the header from the basiclock to the object) // while inflation is in-progress. This protocol avoids races that might // would otherwise permit hashCode values to change or "flicker" for an object. // Critically, while object->mark is 0 mark->displaced_mark_helper() is stable. // 0 serves as a "BUSY" inflate-in-progress indicator // fetch the displaced mark from the owner‘s stack. // The owner can‘t die or unwind past the lock while our INFLATING // object is in the mark. Furthermore the owner can‘t complete // an unlock on the object, either. markOop dmw = mark->displaced_mark_helper() ; assert (dmw->is_neutral(), "invariant") ; //CAS成功,设置ObjectMonitor的_header、_owner和_object等 // Setup monitor fields to proper values -- prepare the monitor m->set_header(dmw) ; // Optimization: if the mark->locker stack address is associated // with this thread we could simply set m->_owner = Self and // m->OwnerIsThread = 1. Note that a thread can inflate an object // that it has stack-locked -- as might happen in wait() -- directly // with CAS. That is, we can avoid the xchg-NULL .... ST idiom. m->set_owner(mark->locker()); m->set_object(object); // TODO-FIXME: assert BasicLock->dhw != 0. // Must preserve store ordering. The monitor state must // be stable at the time of publishing the monitor address. guarantee (object->mark() == markOopDesc::INFLATING(), "invariant") ; object->release_set_mark(markOopDesc::encode(m)); // Hopefully the performance counters are allocated on distinct cache lines // to avoid false sharing on MP systems ... if (ObjectMonitor::_sync_Inflations != NULL) ObjectMonitor::_sync_Inflations->inc() ; TEVENT(Inflate: overwrite stacklock) ; if (TraceMonitorInflation) { if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", (void *) object, (intptr_t) object->mark(), object->klass()->external_name()); } } return m ; } // CASE: neutral 无锁 // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. // If we know we‘re inflating for entry it‘s better to inflate by swinging a // pre-locked objectMonitor pointer into the object header. A successful // CAS inflates the object *and* confers ownership to the inflating thread. // In the current implementation we use a 2-step mechanism where we CAS() // to inflate and then CAS() again to try to swing _owner from NULL to Self. // An inflateTry() method that we could call from fast_enter() and slow_enter() // would be useful. assert (mark->is_neutral(), "invariant"); ObjectMonitor * m = omAlloc (Self) ; // prepare m for installation - set monitor to initial state m->Recycle(); m->set_header(mark); m->set_owner(NULL); m->set_object(object); m->OwnerIsThread = 1 ; m->_recursions = 0 ; m->_Responsible = NULL ; m->_SpinDuration = ObjectMonitor::Knob_SpinLimit ; // consider: keep metastats by type/class if (Atomic::cmpxchg_ptr (markOopDesc::encode(m), object->mark_addr(), mark) != mark) { m->set_object (NULL) ; m->set_owner (NULL) ; m->OwnerIsThread = 0 ; m->Recycle() ; omRelease (Self, m, true) ; m = NULL ; continue ; // interference - the markword changed - just retry. // The state-transitions are one-way, so there‘s no chance of // live-lock -- "Inflated" is an absorbing state. } // Hopefully the performance counters are allocated on distinct // cache lines to avoid false sharing on MP systems ... if (ObjectMonitor::_sync_Inflations != NULL) ObjectMonitor::_sync_Inflations->inc() ; TEVENT(Inflate: overwrite neutral) ; if (TraceMonitorInflation) { if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", (void *) object, (intptr_t) object->mark(), object->klass()->external_name()); } } return m ; } }
1、整个膨胀过程在自旋下完成;
2、mark->has_monitor()方法判断当前是否为重量级锁,即Mark Word的锁标识位为 10,如果当前状态为重量级锁,执行步骤(3),否则执行步骤(4);
3、mark->monitor()方法获取指向ObjectMonitor的指针,并返回,说明膨胀过程已经完成;
4、如果当前锁处于膨胀中,说明该锁正在被其它线程执行膨胀操作,则当前线程就进行自旋等待锁膨胀完成,这里需要注意一点,虽然是自旋操作,但不会一直占用cpu资源,每隔一段时间会通过os::NakedYield方法放弃cpu资源,或通过park方法挂起;如果其他线程完成锁的膨胀操作,则退出自旋并返回;
5、如果当前是轻量级锁状态,即锁标识位为 00,膨胀过程如下:
6、如果是无锁,重置监视器值;
//创建一个啥都没有的类: public class TestDemo {} public class DemoExample { static TestDemo testDemo; public static void main(String[] args) throws Exception { //此处睡眠50000ms,取消jvm默认偏向锁延迟4000ms Thread.sleep(5000); testDemo= new TestDemo(); //hash计算? //testDemo.hashCode(); System.out.println("befor lock"); //无锁:偏向锁? System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); synchronized (testDemo){ System.out.println("lock ing"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } System.out.println("after lock"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } }
运行结果:
befor lock OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total lock ing com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 80 80 ac (00000101 10000000 10000000 10101100) (-1400864763) 4 4 (object header) 8d 7f 00 00 (10001101 01111111 00000000 00000000) (32653) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total after lock com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 80 80 ac (00000101 10000000 10000000 10101100) (-1400864763) 4 4 (object header) 8d 7f 00 00 (10001101 01111111 00000000 00000000) (32653) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
二、在对象进行hashcode计算之后就会输出下面的结果(也就是代码的这块testDemo.hashCode()去掉注释,进行hashcode运算):
befor lock com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total lock ing com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) f8 28 4b 0c (11111000 00101000 01001011 00001100) (206252280) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total after lock com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 80 80 ac (00000101 10000000 10000000 10101100) (-1400864763) 4 4 (object header) 8d 7f 00 00 (10001101 01111111 00000000 00000000) (32653) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
product(intx, BiasedLockingBulkRebiasThreshold, 20, "Threshold of number of revocations per type to try to " "rebias all objects in the heap of that type") range(0, max_intx) constraint(BiasedLockingBulkRebiasThresholdFunc,AfterErgo) \
JVM源码:
product(intx, BiasedLockingBulkRevokeThreshold, 40, "Threshold of number of revocations per type to permanently " "revoke biases of all objects in the heap of that type") range(0, max_intx) constraint(BiasedLockingBulkRevokeThresholdFunc,AfterErgo)
public class TestDemo { } public class DemoExample4 { public static void main(String[] args) throws InterruptedException { test1(); } public class DemoExample5 { public static void main(String[] args) throws InterruptedException { test1(); } /** * 仅证明批量重偏向 * @throws InterruptedException */ public static void test1() throws InterruptedException { List<TestDemo> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add(new TestDemo()); } Thread t1 = new Thread(()->{ System.out.println("加锁前 get(0) 应该是无锁可偏向 "+ ClassLayout.parseInstance(list.get(0)).toPrintable()); for (TestDemo a:list ) { synchronized (a){ System.out.print("加锁 >"); } } System.out.println(); System.out.println("加锁后 get(0) 应该是偏向锁"+ClassLayout.parseInstance(list.get(0)).toPrintable()); try { TimeUnit.SECONDS.sleep(1000);//这里不让线程死,防止线程ID复用 } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); TimeUnit.SECONDS.sleep(5); Thread t2 = new Thread(()->{ for (int i = 0; i < 40; i++) { TestDemo a = list.get(i); synchronized (a){ System.out.print("加锁 >"); } if (i==18){ System.out.println(); System.out.println("加锁后 get(18) 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } if (i==19){ //开始重偏向 System.out.println(); System.out.println("加锁后 get(19) 应该是偏向锁 "+ClassLayout.parseInstance(list.get(i)).toPrintable()); System.out.println("加锁后 get(0) 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(0)).toPrintable()); System.out.println("加锁后 get(99) 应该是偏向锁 偏向t1 "+ClassLayout.parseInstance(list.get(99)).toPrintable()); } if (i==20){ System.out.println(); System.out.println("加锁后 get(20) 应该是偏向锁 "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } } }); t2.start(); } }
运行并分析结果:
com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 > 加锁后 get(0) 应该是偏向锁com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 30 8a 73 (00000101 00110000 10001010 01110011) (1938436101) 4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 > 加锁后 get(18) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 > 加锁后 get(19) 应该是偏向锁 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 41 0b 75 (00000101 01000001 00001011 01110101) (1963671813) 4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(0) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(99) 应该是偏向锁 偏向t1 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 30 8a 73 (00000101 00110000 10001010 01110011) (1938436101) 4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 > 加锁后 get(20) 应该是偏向锁 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 41 0b 75 (00000101 01000001 00001011 01110101) (1963671813) 4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >
public class TestDemo { } public class DemoExample7 { public static void main(String[] args) throws Exception { List<TestDemo> list = new ArrayList<>(); //初始化数据 for (int i = 0; i < 100; i++) { list.add(new TestDemo()); } Thread t1 = new Thread() { String name = "1"; public void run() { System.out.printf(name); for (TestDemo a : list) { synchronized (a) { if (a == list.get(10)) { System.out.println("t1 预期是偏向锁" + 10 + ClassLayout.parseInstance(a).toPrintable()); } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); Thread.sleep(5000); System.out.println("main 预期是偏向锁" + 10 + ClassLayout.parseInstance(list.get(10)).toPrintable()); Thread t2 = new Thread() { String name = "2"; public void run() { System.out.printf(name); for (int i = 0; i < 100; i++) { TestDemo a = list.get(i); // hack 为了在批量重偏向发生后再次加锁,前面使用了轻量级锁的对象 if (i == 20) { a = list.get(9); } synchronized (a) { if (i == 10) { //已经经过偏向锁撤销,并使用轻量级锁的对象,释放后 状态依为001 无锁状态 System.out.println("t2 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list.get(1)).toPrintable()); //因为和t1交替使用对象a 没有发生竞争,但偏向锁已偏向,另外不满足重偏向条件,所以使用轻量级锁 System.out.println("t2 i=10 get(i) 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable()); } if (i == 19) { //已经经过偏向锁撤销,并使用轻量级锁的对象,在批量重偏向发生后。不会影响现有的状态 状态依然为001 System.out.println("t2 i=19 get(10)预期是无锁" + 10 + ClassLayout.parseInstance(list.get(10)).toPrintable()); //满足重偏向条件后,已偏向的对象可以重新使用偏向锁 将线程id指向当前线程,101 System.out.println("t2 i=19 get(i) 满足重偏向条件20 预期偏向锁 " + i + ClassLayout.parseInstance(a).toPrintable()); //满足重偏向条件后,已偏向还为需要加锁的对象依然偏向线程1 因为偏向锁的撤销是发生在下次加锁的时候。这里没有执行到同步此对象,所以依然偏向t1 System.out.println("t2 i=19 get(i) 满足重偏向条件20 但后面的对象没有被加锁,所以依旧偏向t1 " + i + ClassLayout.parseInstance(list.get(40)).toPrintable()); } if (i == 20) { //满足重偏向条件后,再次加锁之前使用了轻量级锁的对象,依然轻量级锁,证明重偏向这个状态只针对偏向锁。已经发生锁升级的,不会退回到偏向锁 System.out.println("t2 i=20 满足偏向条件之后,之前被设置为无锁状态的对象,不可偏向,这里使用的是轻量级锁 get(9)预期是轻量级锁 " + ClassLayout.parseInstance(a).toPrintable()); } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t2.start(); Thread.sleep(5000); } }
运行并分析结果:
t1 预期是偏向锁10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 78 86 af (00000101 01111000 10000110 10101111) (-1350141947) 4 4 (object header) f6 7f 00 00 (11110110 01111111 00000000 00000000) (32758) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total main 预期是偏向锁 10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 78 86 af (00000101 01111000 10000110 10101111) (-1350141947) 4 4 (object header) f6 7f 00 00 (11110110 01111111 00000000 00000000) (32758) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 2t2 i=10 get(1)预期是无锁 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=10 get(i) 预期轻量级锁 10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 69 42 08 (00001000 01101001 01000010 00001000) (138569992) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=19 get(10)预期是无锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=19 get(i) 满足重偏向条件20 预期偏向锁 19com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 71 95 ae (00000101 01110001 10010101 10101110) (-1365937915) 4 4 (object header) f6 7f 00 00 (11110110 01111111 00000000 00000000) (32758) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=19 get(i) 满足重偏向条件20 但后面的对象没有被加锁,所以依旧偏向t1 19com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 78 86 af (00000101 01111000 10000110 10101111) (-1350141947) 4 4 (object header) f6 7f 00 00 (11110110 01111111 00000000 00000000) (32758) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=20 满足偏向条件之后,之前被设置为无锁状态的对象,不可偏向,这里使用的是轻量级锁 get(9)预期是轻量级锁 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 69 42 08 (00001000 01101001 01000010 00001000) (138569992) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 05 d6 00 f8 (00000101 11010110 00000000 11111000) (-134162939) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
public class TestDemo { } public class DemoExample6 { public static void main(String[] args) throws InterruptedException { test2(); } /** * 证明偏量偏向撤销 * @throws InterruptedException */ public static void test2() throws InterruptedException { List<TestDemo> list = new ArrayList<TestDemo>(); for (int i = 0; i < 100; i++) { list.add(new TestDemo()); } Thread t1 = new Thread(()->{ System.out.println("加锁前 get(0) 应该是无锁可偏向 "+ClassLayout.parseInstance(list.get(0)).toPrintable()); for (TestDemo a:list ) { synchronized (a){ System.out.print("加锁 >"); } } System.out.println(); System.out.println("加锁后 get(0) 应该是偏向锁"+ClassLayout.parseInstance(list.get(0)).toPrintable()); try { TimeUnit.SECONDS.sleep(1000);//这里不让线程死,防止线程ID复用 } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); TimeUnit.SECONDS.sleep(5); Thread t2 = new Thread(()->{ for (int i = 0; i < 100; i++) { TestDemo a = list.get(i); synchronized (a){ System.out.println(Thread.currentThread().getId()+"加锁 >"); } try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if (i==9){//这里刚好是第19个上锁的(同样是第19个偏向锁升级的) System.out.println(); System.out.println("加锁后 get(9) 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } if (i==10){//这里刚好是第21个上锁的 System.out.println(); System.out.println("加锁后 get(10) 应该是偏向锁 偏向t2 "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } if (i==50){//50开始升级为轻量级锁(同样是第21个偏向锁升级的) System.out.println(); System.out.println("加锁后 get(50) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } if (i==59){//60(同样是第39个偏向锁升级的) System.out.println(); System.out.println("加锁后 get(59) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable()); } if (i==69){//69(同样是第59个偏向锁升级的) System.out.println(); System.out.println("加锁后 get(69) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable()); TestDemo a1 = new TestDemo(); synchronized (a1){ System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable()); } } } }); Thread t3 = new Thread(()->{ for (int i = 99; i >= 0; i--) { TestDemo a = list.get(i); synchronized (a){ System.out.println(Thread.currentThread().getId()+"加锁 >"); } try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } /** * 重点:重偏向撤销 */ if (i==40){//40升级为轻量级锁(同样是第40个偏向锁升级的,这时候发生偏向撤销) System.out.println(); System.out.println("加锁后 get("+i+") 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(0)).toPrintable()); TestDemo a1 = new TestDemo(); synchronized (a1){ System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable()); } } if (i==30){//39升级为轻量级锁(同样是第42个偏向锁升级的) System.out.println(); System.out.println("加锁后 get("+i+") 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(0)).toPrintable()); TestDemo a1 = new TestDemo(); synchronized (a1){ System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable()); } } } }); t2.start(); TimeUnit.MILLISECONDS.sleep(50); t3.start(); } }
运行结果(截取部分):
加锁前 get(0) 应该是无锁可偏向 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 > 加锁后 get(0) 应该是偏向锁com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 e0 84 08 (00000101 11100000 10000100 00001000) (142925829) 4 4 (object header) b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(9) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 15加锁 > 加锁后 get(90) 应该是偏向锁 偏向t3com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 89 01 0c (00000101 10001001 00000001 00001100) (201427205) 4 4 (object header) b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(10) 应该是偏向锁 偏向t2 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 b1 0a 08 (00000101 10110001 00001010 00001000) (134918405) 4 4 (object header) b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 15加锁 > 加锁后 get(89) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(50) 无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 15加锁 > 加锁后 get(49) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(59) 无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 15加锁 > 加锁后 get(40) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 48 18 a6 09 (01001000 00011000 10100110 00001001) (161880136) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 加锁后 get(69) 无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 50 e8 95 09 (01010000 11101000 10010101 00001001) (160819280) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 15加锁 > 加锁后 get(30) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 48 18 a6 09 (01001000 00011000 10100110 00001001) (161880136) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
案例二:
public class TestDemo { } public class DemoExample8 { public static void main(String[] args) throws Exception { List<TestDemo> list = new ArrayList<>(); List<TestDemo> list2 = new ArrayList<>(); List<TestDemo> list3 = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add(new TestDemo()); list2.add(new TestDemo()); list3.add(new TestDemo()); } //偏向锁 System.out.println("初始状态" + 10 + ClassLayout.parseClass(TestDemo.class).toPrintable()); Thread t1 = new Thread() { String name = "1"; public void run() { System.out.printf(name); for (TestDemo a : list) { synchronized (a) { if (a == list.get(10)) { //偏向锁 System.out.println("t1 预期是偏向锁" + 10 + ClassLayout.parseInstance(a).toPrintable()); } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); Thread.sleep(5000); //偏向锁 System.out.println("main 预期是偏向锁" + 10 + ClassLayout.parseInstance(list.get(10)).toPrintable()); Thread t2 = new Thread() { String name = "2"; public void run() { System.out.printf(name); for (int i = 0; i < 100; i++) { TestDemo a = list.get(i); synchronized (a) { if (a == list.get(10)) { System.out.println("t2 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list.get(1)).toPrintable());//偏向锁 System.out.println("t2 i=10 get(10) 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } if (a == list.get(19)) { System.out.println("t2 i=19 get(10)预期是无锁" + 10 + ClassLayout.parseInstance(list.get(10)).toPrintable());//偏向锁 System.out.println("t2 i=19 get(19) 满足重偏向条件20 预期偏向锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 System.out.println("类的对象累计撤销达到20"); } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t2.start(); Thread.sleep(5000); Thread t3 = new Thread() { String name = "3"; public void run() { System.out.printf(name); for (TestDemo a : list2) { synchronized (a) { if (a == list2.get(10)) { System.out.println("t3 预期是偏向锁" + 10 + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t3.start(); Thread.sleep(5000); Thread t4 = new Thread() { String name = "4"; public void run() { System.out.printf(name); for (int i = 0; i < 100; i++) { TestDemo a = list2.get(i); synchronized (a) { if (a == list2.get(10)) { System.out.println("t4 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list2.get(1)).toPrintable());//偏向锁 System.out.println("t4 i=10 get(10) 当前不满足重偏向条件 20 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } if (a == list2.get(19)) { System.out.println("t4 i=19 get(10)预期是无锁" + 10 + ClassLayout.parseInstance(list2.get(10)).toPrintable());//偏向锁 System.out.println("t4 i=19 get(19) 当前满足重偏向条件 20 但A类的对象累计撤销达到40 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 System.out.println("类的对象累计撤销达到40"); } if (a == list2.get(20)) { System.out.println("t4 i=20 get(20) 当前满足重偏向条件 20 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } } } } }; t4.start(); Thread.sleep(5000); System.out.println("main 预期是偏向锁" + 10 + ClassLayout.parseInstance(list3.get(0)).toPrintable());//偏向锁 Thread t5 = new Thread() { String name = "5"; public void run() { System.out.printf(name); for (TestDemo a : list3) { synchronized (a) { if (a == list3.get(10)) { System.out.println("t5 预期是轻量级锁,类的对象累计撤销达到40 不可以用偏向锁了" + 10 + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t5.start(); Thread.sleep(5000); System.out.println("main 预期是偏向锁" + 10 + ClassLayout.parseInstance(list.get(10)).toPrintable());//偏向锁 Thread t6 = new Thread() { String name = "6"; public void run() { System.out.printf(name); for (int i = 0; i < 100; i++) { TestDemo a = list3.get(i); synchronized (a) { if (a == list3.get(10)) { System.out.println("t6 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list3.get(1)).toPrintable());//偏向锁 System.out.println("t6 i=10 get(10) 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } if (a == list3.get(19)) { System.out.println("t6 i=19 get(10)预期是无锁" + 10 + ClassLayout.parseInstance(list3.get(10)).toPrintable());//偏向锁 System.out.println("t6 i=19 get(19) 满足重偏向条件20 但类的对象累计撤销达到40 不可以用偏向锁了 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁 } } } try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t6.start(); Thread.sleep(5000); System.out.println("由于撤销锁次数达到默认的 BiasedLockingBulkRevokeThreshold=40 这里实例化的对象 是无锁状态" + ClassLayout.parseInstance(new TestDemo()).toPrintable());//偏向锁 System.out.println("撤销偏向后状态" + 10 + ClassLayout.parseInstance(new TestDemo()).toPrintable());//偏向锁 } }
运行结果:
初始状态10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 1t1 预期是偏向锁10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 e0 86 8e (00000101 11100000 10000110 10001110) (-1903763451) 4 4 (object header) ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total main 预期是偏向锁10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 e0 86 8e (00000101 11100000 10000110 10001110) (-1903763451) 4 4 (object header) ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 2t2 i=10 get(1)预期是无锁com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=10 get(10) 预期轻量级锁 10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 99 7a 03 (00001000 10011001 01111010 00000011) (58366216) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=19 get(10)预期是无锁10 com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t2 i=19 get(19) 满足重偏向条件20 预期偏向锁 19com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 09 90 91 (00000101 00001001 10010000 10010001) (-1852831483) 4 4 (object header) ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 类的对象累计撤销达到20 3t3 预期是偏向锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 09 89 90 (00000101 00001001 10001001 10010000) (-1870067451) 4 4 (object header) ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 4t4 i=10 get(1)预期是无锁com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t4 i=10 get(10) 当前不满足重偏向条件 20 预期轻量级锁 10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t4 i=19 get(10)预期是无锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t4 i=19 get(19) 当前满足重偏向条件 20 但A类的对象累计撤销达到40 预期轻量级锁 19com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 类的对象累计撤销达到40 t4 i=20 get(20) 当前满足重偏向条件 20 预期轻量级锁 20com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total main 预期是偏向锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 5t5 预期是轻量级锁,A类的对象累计撤销达到40 不可以用偏向锁了10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total main 预期是偏向锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 6t6 i=10 get(1)预期是无锁com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t6 i=10 get(10) 预期轻量级锁 10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 29 ab 03 (00001000 00101001 10101011 00000011) (61548808) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t6 i=19 get(10)预期是无锁10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t6 i=19 get(19) 满足重偏向条件20 但A类的对象累计撤销达到40 不可以用偏向锁了 19com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 08 29 ab 03 (00001000 00101001 10101011 00000011) (61548808) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 由于类撤销锁次数达到默认的 BiasedLockingBulkRevokeThreshold=40 这里实例化的对象 是无锁状态com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 撤销偏向后状态10com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
以上案例证实了偏向锁的批量重偏向和批量撤销,接下来我们讲解轻量级锁;
分析一个由偏向锁膨胀成轻量级锁的案例:
public class TestDemo { } public class DemoExample9 { public static void main(String[] args) throws Exception { TestDemo testDemo = new TestDemo(); //子线程 Thread t1 = new Thread(){ @Override public void run() { synchronized (testDemo){ System.out.println("t1 lock ing"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } } }; t1.join(); //主线程 synchronized (testDemo){ System.out.println("main lock ing"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } } }
运行结果(两个线程交替执行的情况下):
main lock ing com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) e8 48 95 09 (11101000 01001000 10010101 00001001) (160778472) 4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672) 8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
分析一个由轻量级锁膨胀成重量级锁的案例:
public class TestDemo { } public class DemoExample9 { public static void main(String[] args) throws Exception { TestDemo testDemo = new TestDemo(); Thread t1 = new Thread(){ @Override public void run() { synchronized (testDemo){ System.out.println("t1 lock ing"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } } }; t1.start(); synchronized (testDemo){ System.out.println("main lock ing"); System.out.println(ClassLayout.parseInstance(testDemo).toPrintable()); } } }
运行结果:
main lock ing com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 5a ad 00 b0 (01011010 10101101 00000000 10110000) (-1342132902) 4 4 (object header) cf 7f 00 00 (11001111 01111111 00000000 00000000) (32719) 8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total t1 lock ing com.boke.TestDemo object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 5a ad 00 b0 (01011010 10101101 00000000 10110000) (-1342132902) 4 4 (object header) cf 7f 00 00 (11001111 01111111 00000000 00000000) (32719) 8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160) 12 4 (loss due to the next object alignment)
到此为止本篇就讲完了锁的膨胀过程:
// We create a list of in-use monitors for each thread. // // deflate_thread_local_monitors() scans a single thread‘s in-use list, while // deflate_idle_monitors() scans only a global list of in-use monitors which // is populated only as a thread dies (see omFlush()). // // These operations are called at all safepoints, immediately after mutators // are stopped, but before any objects have moved. Collectively they traverse // the population of in-use monitors, deflating where possible. The scavenged // monitors are returned to the monitor free list. // // Beware that we scavenge at *every* stop-the-world point. Having a large // number of monitors in-use could negatively impact performance. We also want // to minimize the total # of monitors in circulation, as they incur a small // footprint penalty. // // Perversely, the heap size -- and thus the STW safepoint rate -- // typically drives the scavenge rate. Large heaps can mean infrequent GC, // which in turn can mean large(r) numbers of objectmonitors in circulation. // This is an unfortunate aspect of this design.
文献来源于:https://www.cnblogs.com/yuhangwang/p/11295940.html
原文链接:https://www.cnblogs.com/JonaLin/p/11571482.html#top
synchronized(三) 锁的膨胀过程(锁的升级过程)深入剖析
标签:repr with swing 对齐 recursion 相等 rac sla mon
原文地址:https://www.cnblogs.com/yrjns/p/12152975.html