警告??:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳。
public class TestDemo {
}
public class DemoExample1 {
static TestDemo testDemo;
public static void main(String[] args) throws Exception {
testDemo= new TestDemo();
synchronized (testDemo){
System.out.println("lock ing");
testDemo.hashCode();
System.out.println(ClassLayout.parseInstance(testDemo).toPrintable());
}
}
}
javap -c DemoExample1.class
public class DemoExample3 {
public int sharedState;
public void nonSafeAction() {
while (sharedState < 100000) {
int former = sharedState++;
int latter = sharedState;
if (former != latter - 1) {
System.out.println("Observed data race, former is " +
former + ", " + "latter is " + latter);
}
}
}
public static void main(String[] args) throws InterruptedException {
final DemoExample3 demoExample3 = new DemoExample3();
Thread thread1 = new Thread() {
@Override
public void run() {
demoExample3.nonSafeAction();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
demoExample3.nonSafeAction();
}
};
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
public class DemoExample3 {
public int sharedState;
public void nonSafeAction() {
while (sharedState < 100000) {
synchronized (this) {
int former = sharedState++;
int latter = sharedState;
if (former != latter - 1) {
System.out.println("Observed data race, former is " +
former + ", " + "latter is " + latter);
}
}
}
}
public static void main(String[] args) throws InterruptedException {
final DemoExample3 demoExample3 = new DemoExample3();
Thread thread1 = new Thread() {
@Override
public void run() {
demoExample3.nonSafeAction();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
demoExample3.nonSafeAction();
}
};
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
这次看下加上synchronized关键字的打印出来的结果:
// 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
//fast_enter 是我们熟悉的完整锁获取路径
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
// -----------------------------------------------------------------------------
// 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());
}
}
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) \
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();
}
}
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);
}
}
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();
}
}
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());//偏向锁
}
}
撤销偏向后状态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());
}
}
}
分析一个由轻量级锁膨胀成重量级锁的案例:
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());
}
}
}
运行结果:
java并发笔记之四synchronized 锁的膨胀过程(锁的升级过程)深入剖析
原文:https://www.cnblogs.com/yuhangwang/p/11295940.html