并发编程(十七)Synchronized锁升级-偏向锁(下)-例3

75 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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

跟之前一样,我们一块一块分析:

image.png 我们可以看到A线程加锁前锁对象是偏向锁,并且并没有记录线程id等信息,锁对象位全都是0,

image.png 当A线程进入同步代码块后,此时锁为偏向锁,并且记录了线程id。

image.png 此时A线程还处于睡眠中并没有释放锁,B线程已经启动了,B线程开始竞争前,我们发现此时锁还是偏向锁,并且记录的是A线程id。

image.png 注意此时A线程还在睡眠并没有释放锁,B线程开始真正的锁竞争,我们可以看到此时的锁对象后三位是010,代表的重量级锁!

2.总结

A线程获取偏向锁,并且A线程没有释放偏向锁(),还在syhnc的代码块里边。B线程此时过来争抢偏向锁,会直接升级为重量级锁。