开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情
1.偏向锁竞争
假设一种情况A线程获取偏向锁,并且A线程释放锁后线程并没有死亡。B线程争抢偏向锁,此时B线程的锁状态是什么样子的? 举个例子:
public class SyncSyncLockRelease1 {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
System.out.println("====A 加锁前==="+ClassLayout.parseInstance(obj).toPrintable());
Thread A = new Thread() {
@SneakyThrows
@Override
public void run() {
synchronized (obj) {
System.out.println("===A 加锁中==="+ClassLayout.parseInstance(obj).toPrintable());
}
Thread.sleep(2000);
}
};
A.start();
Thread.sleep(500);
System.out.println("====B加锁前==="+ClassLayout.parseInstance(obj).toPrintable());
Thread B = new Thread() {
@SneakyThrows
@Override
public void run() {
synchronized (obj) {
System.out.println("====B加锁中==="+ClassLayout.parseInstance(obj).toPrintable());
Thread.sleep(1000);
}
}
};
B.start();
}
}
执行效果如下:
====A 加锁前===java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
===A 加锁中===java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 20 ee 18 (00000101 00100000 11101110 00011000) (418258949)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
====B加锁前===java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 20 ee 18 (00000101 00100000 11101110 00011000) (418258949)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
====B加锁中===java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 10 f6 5b 1b (00010000 11110110 01011011 00011011) (459011600)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
我们一块一块分析。
当程序开始执行时,A线程会先开启,由于主线程会睡眠500毫秒后才启动B线程,所以B线程还未开启,A线程执行效果,可以看到A线程此时还是偏向锁,但是未记录线程id。
当线程A进入同步代码块时,此时锁状态是偏向锁,并且记录了线程id。
当B线程开始执行,并进入同步代码块前,我们可以看到此时锁还是偏向锁,并且记录的锁id还是B线程的。
当B线程进入同步代码块时,我们可以看到,B竞争锁后,锁升级为轻量级锁,并且记录了锁记录指针。
2.总结
A线程获取偏向锁,并且A线程释放了锁,但是A线程并没有死亡还在活跃状态。B线程过来争抢,会直接升级为轻量级锁。