开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
1.偏向锁竞争
假设一种情况A线程获取偏向锁,并且A线程死亡退出。B线程争抢偏向锁,此时B线程的锁状态是什么样子的? 我给大家举个例子:
public class SyncSyncLockRelease {
static Thread A;
static Thread B;
public static void main(String[] args) {
final List<Object> list = new ArrayList<>();
A = new Thread() {
@SneakyThrows
@Override
public void run() {
Object a = new Object();
list.add(a);
System.out.println("AAAA加锁前" + ClassLayout.parseInstance(a).toPrintable());
synchronized (a) {
System.out.println("AAAA加锁中" + ClassLayout.parseInstance(a).toPrintable());
}
System.out.println("AAAA加锁后" + ClassLayout.parseInstance(a).toPrintable());
//防止竞争 执行完后唤醒线程B/ 确保A线程 死亡 Terminated
LockSupport.unpark(B);
}
};
B = new Thread() {
@Override
public void run() {
LockSupport.park();
Object a = list.get(0);
System.out.println("线程BBBB加锁前" + ClassLayout.parseInstance(a).toPrintable());
synchronized (a) {
System.out.println("线程BBBB加锁中" + ClassLayout.parseInstance(a).toPrintable());
}
System.out.println("线程BBBB加锁后" + ClassLayout.parseInstance(a).toPrintable());
System.out.println("新产生的对象" + ClassLayout.parseInstance(new Object()).toPrintable());
}
};
A.start();
B.start();
}
}
执行效果如下:
AAAA加锁前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
AAAA加锁中java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 50 5c 20 (00000101 01010000 01011100 00100000) (542920709)
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
AAAA加锁后java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 50 5c 20 (00000101 01010000 01011100 00100000) (542920709)
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
线程BBBB加锁前java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 50 5c 20 (00000101 01010000 01011100 00100000) (542920709)
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
线程BBBB加锁中java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 58 f4 b8 21 (01011000 11110100 10111000 00100001) (565769304)
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
线程BBBB加锁后java.lang.Object 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) 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
新产生的对象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
我们一块一块分析。
当程序开始执行时,AB线程都开启后,B线程由于LockSupport.park()处于阻塞状态,A线程执行效果如下,说明:
当A线程执行完毕后,LockSupport.unpark(B)唤醒B线程,此时B线程开始有打印结果,我们继续分析:
这时我们可以看到,线程B加锁中为轻量级锁,加锁后为无锁,这是不是就代表着锁降级了呢?
不是的,synchronize锁只有升级没有降级,因为我们的锁升级完全是jvm控制,那么锁降级主要是没法掌控降级的临界点,把握不好尺度,不知道如何高效的降级或者降到什么级别。这里是轻量级锁释放了锁,此时这个对象就是无锁状态。
如果再新建一个对象,我们可以看到新产生的对象是偏向锁状态,并且是否为偏向锁前面都是0。
2.总结
A线程获取偏向锁,并且A线程死亡退出。B线程争抢偏向锁,会直接升级当前对象的锁为轻量级锁。这只是针对我们争抢了一次。