关于Synchronized不同锁升级情况

53 阅读5分钟

我们知道Synchronized存在锁升级的情况

  1. 无锁状态
  2. 匿名偏向锁状态
  3. 偏向锁状态
  4. 轻量级锁状态
  5. 重量级锁状态

通过查看锁对象的markword的后三位来确定,来确定锁状态

锁类型偏向锁锁标志总体标志
无锁001001
偏向锁101101
轻量级锁000000
重量级锁010010

这里我们还是通过openjdk的jol来查看markword,maven引入

<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>
  <version>0.9</version>
</dependency>

无锁

public void printNoLock(){
    System.out.println("打印无锁状态");
    System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
    System.out.println("==============================================================");
}

打印日志使用**标记出来就是锁标识位,当前001为无锁状态

 java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000**001** 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           00 1c 5d 75 (00000000 00011100 01011101 01110101) (1969036288)
     12     4        (object header)                           e5 01 00 00 (11100101 00000001 00000000 00000000) (485)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

匿名偏向锁

偏向锁启动有4秒时延

public void printAnonymousBiasLock(){
    System.out.println("=====================打印匿名偏向锁状态=====================");
    try {
        Thread.sleep(5000L);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    Object object = new Object();
    System.out.println(ClassLayout.parseInstance(object).toPrintable());
    System.out.println("==============================================================");
}

打印日志使用**标记出来就是锁标识位,当前101为偏向锁状态,并且后面都是0000没有记录偏向锁的归属

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000**101** 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

偏向锁

public void printBiasLock(){
    System.out.println("=====================打印偏向锁状态=====================");
    try {
        Thread.sleep(5000L);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    Object object = new Object();
    synchronized (object){
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
    }
    System.out.println("==============================================================");
}

打印日志使用**标记出来就是锁标识位,当前101为偏向锁状态,并且后面不是0000,记录偏向锁的归属

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 49 0e 76 (00000**101** 01001001 00001110 01110110) (1980647685)
      4     4        (object header)                           e9 01 00 00 (11101001 00000001 00000000 00000000) (489)
      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 void printLightWeightLock(){
    System.out.println("=====================打印无锁升级成轻量级锁状态=====================");
    Object object = new Object();
    System.out.println(ClassLayout.parseInstance(object).toPrintable());
    synchronized (object){
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
    }
    System.out.println("==============================================================");
}

进入轻量级锁的方式有很多,比如如果偏向锁未启动,直接资源竞争就会直接进入轻量级锁状态

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           48 f6 2f 27 (01001**000** 11110110 00101111 00100111) (657454664)
      4     4        (object header)                           03 00 00 00 (00000011 00000000 00000000 00000000) (3)
      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 void printHeavyWeightLock(){
    System.out.println("打印重量级锁状态");
    Object object = new Object();
    for(int i=0;i<10;i++){
        new Thread(()->{
            synchronized (object){
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }).start();
    }

    System.out.println("==============================================================");
}

锁竞争激烈就会申请为重量级锁

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           fa b8 48 41 (11111**010** 10111000 01001000 01000001) (1095284986)
      4     4        (object header)                           a9 02 00 00 (10101001 00000010 00000000 00000000) (681)
      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