开启掘金成长之旅!这是我参与「掘金日新计划 · 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 98 54 20 (00000101 10011000 01010100 00100000) (542414853)
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 98 54 20 (00000101 10011000 01010100 00100000) (542414853)
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) ea 33 b8 1b (11101010 00110011 10111000 00011011) (465056746)
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
Process finished with exit code 0
跟之前一样,我们一块一块分析:
我们可以看到A线程加锁前锁对象是偏向锁,并且并没有记录线程id等信息,锁对象位全都是0,
当A线程进入同步代码块后,此时锁为偏向锁,并且记录了线程id。
此时A线程还处于睡眠中并没有释放锁,B线程已经启动了,B线程开始竞争前,我们发现此时锁还是偏向锁,并且记录的是A线程id。
注意此时A线程还在睡眠并没有释放锁,B线程开始真正的锁竞争,我们可以看到此时的锁对象后三位是010,代表的重量级锁!
2.总结
A线程获取偏向锁,并且A线程没有释放偏向锁(),还在syhnc的代码块里边。B线程此时过来争抢偏向锁,会直接升级为重量级锁。