synchronized锁的验证 [无锁-」偏向锁-」轻量级锁-」重量级锁-」无锁过程]

锁的验证- 无锁->偏向锁->轻量级锁->重量级锁->无锁过程

一、JVM 设置参数

# 开启偏向锁
-XX:+UseBiasedLocking
# 关闭偏向锁延迟
-XX:BiasedLockingStartupDelay=0
# 查看所有的 JVM 参数
-XX:+PrintFlagsFinal
# 设置重偏向阈值
-XX:BiasedLockingBulkRebiasThreshold=20
# 批量重偏向距离上次批量重偏向的后重置的延迟时间
-XX:BiasedLockingDecayTime=25000
# 设置批量撤销阈值
-XX:BiasedLockingBulkRevokeThreshold=40

在 JVM 启动的时候会有很多线程在后台运行,例如 GC 线程,Finalizer 线程,VM Thread 线程等,会用到很多同步操作,所以在启动的前 4 秒默认创建的对象都不支持偏向,因为有默认参数

	-XX:BiasedLockingStartupDelay=4000

二、无锁状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4hwbHgh-1594019771902)(/Users/haocongcong/Library/Containers/com.tencent.WeWorkMac/Data/Library/Application Support/WXWork/Data/1688850015369412/Cache/Image/2020-06/无锁二进制.png)]

     public void test1(){
	     Object model2 = new Object();
        System.out.println(ClassLayout.parseInstance(model2).toPrintable());
        System.out.println("hash: -----" + model2.hashCode());
        // 偏向锁
        System.out.println(ClassLayout.parseInstance(model2).toPrintable());
        binaryToDecimal(model2.hashCode());   
     }
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

hash: -----1975358023
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION           VALUE
      0     4        (object header)       01 47 92 bd (00000001 01000111 10010010 10111101) (-1114487039)
      4     4        (object header)       75 00 00 00 (01110101 00000000 00000000 00000000) (117)
      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

header中前8个字节按照平时习惯的从高位到低位的展示为:

00000000 00000000 00000000 01110101 10111101 10010010 01000111 00000001

对照上图。最后3位001,代表无锁状态
中间31位(01110101 10111101 10010010 01000111)换算成10进制,即为上图打印的hash值:1975358023

偏向锁

    public static void main(String[] args) throws InterruptedException {
         //JVM 启动 5 秒后创建对象
        Thread.sleep(5000);
        Object object = new Object();
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
        //偏向锁
        synchronized (object){
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }

    }
//匿名偏向 
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


//偏向锁
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION        VALUE
      0     4        (object header)    05 68 01 b9 (00000101 01101000 00000001 10111001) (-1191090171)
      4     4        (object header)    f7 7f 00 00 (11110111 01111111 00000000 00000000) (32759)
      8     4        (object header)    e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)

偏向锁和hashCode方法

当一个对象已经计算过identity hash code,它就无法进入偏向锁状态;当一个对象当前正处于偏向锁状态,并且需要计算其identity hash code的话,则它的偏向锁会被撤销。
那什么时候对象会计算identity hash code呢?当然是当你调用未覆盖的Object.hashCode()方法或者System.identityHashCode(Object o)时候了。

 public static void main(String[] args) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object model2 = new Object();
        System.out.println(ClassLayout.parseInstance(model2).toPrintable());
        System.out.println("hash: -----" + model2.hashCode());
//        System.out.println("hashcode:: "+Integer.toBinaryString(model2.hashCode()));
        System.out.println("----------after hashcode----------");
        System.out.println(ClassLayout.parseInstance(model2).toPrintable());
        synchronized (model2){
            System.out.println("---------after lock-------");
            model2.hashCode();
            System.out.println(ClassLayout.parseInstance(model2).toPrintable());
        }

    }
    }
//偏向锁
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

hash: -----1911728085
----------after hashcode----------
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 d5 a7 f2 (00000001 11010101 10100111 11110010) (-223881983)
      4     4        (object header)                           71 00 00 00 (01110001 00000000 00000000 00000000) (113)
      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

---------after lock-------
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           d0 a8 4c 04 (11010000 10101000 01001100 00000100) (72132816)
      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      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

轻量级锁

	public static void main(String[] args) throws InterruptedException {
         //JVM 启动 5 秒后创建对象
        Thread.sleep(5000);
        Object object = new Object();

        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 进入偏向锁状态");
            synchronized (object) {
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        });
        t1.start();
        t1.join();

        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + " 进入轻量级锁状态");
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }).start();

    }
	Thread-0 进入偏向锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION         VALUE
      0     4        (object header)     05 e8 18 a8 (00000101 11101000 00011000 10101000) (-1474762747)
      4     4        (object header)     a4 7f 00 00 (10100100 01111111 00000000 00000000) (32676)
      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

Thread-2 进入轻量级锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION        VALUE
      0     4        (object header)    68 c8 0c 06 (01101000 11001000 00001100 00000110) (101501032)
      4     4        (object header)    00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      8     4        (object header)    e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)

#重量级锁

public static void main(String[] args) throws InterruptedException {
        //JVM 启动 5 秒后创建对象
        Thread.sleep(5000);
        Object object = new Object();

        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 进入偏向锁状态");
            synchronized (object) {

                System.out.println(LocalDateTime.now()+",t1锁状态:"+ClassLayout.parseInstance(object).toPrintable());
            }
        });
        t1.setName("t1");
        t1.start();
        t1.join();

        Thread t2 = new Thread(() -> {
            synchronized (object) {
                System.out.println("t2:"+ClassLayout.parseInstance(object).toPrintable());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2锁状态:"+ClassLayout.parseInstance(object).toPrintable());
            }
        });
        t2.setName("t2");
        t2.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread t3 = new Thread(() -> {

            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + " 拿到锁,状态:");
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        });
        t3.setName("t3");
        t3.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after all:"+ClassLayout.parseInstance(object).toPrintable());
    }

输出结果

无锁->偏向锁->轻量级锁->重量级锁->无锁

t1锁状态:java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 40 99 29 (00000101 01000000 10011001 00101001) (697909253)
      4     4        (object header)                           ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
      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

t2:java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 40 99 29 (00000101 01000000 10011001 00101001) (697909253)
      4     4        (object header)                           ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
      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

t2锁状态:java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           4a 97 81 2a (01001010 10010111 10000001 00101010) (713135946)
      4     4        (object header)                           ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
      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

t3 拿到锁,状态:
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           4a 97 81 2a (01001010 10010111 10000001 00101010) (713135946)
      4     4        (object header)                           ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
      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

after all: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

总结一下,其实无锁->偏向锁->轻量级锁->重量级锁的转化过程中没那么复杂,注意记住:
(1)只有一个线程获取锁时,就是偏向锁。
(2)多个线程时,不存在竞争(多个线程顺序执行),轻量级锁。
(3)多个线程存在竞争时重量级锁。
很多时候,偏向锁->轻量级锁->重量级锁的转化过程,基本你只能看见开头和结尾,因为轻量级锁的自旋被优化不会长时间持续进行的,所以你看到的就是偏向锁到重量级锁的过程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章