synchronized锁膨胀笔记

58 篇文章 0 订阅

锁膨胀支持之前,synchronized 在释放和获取锁时都会从用户态转换成核心态,状态转换需要耗费CPU很多时间,所以synchronized是一个重量级操作。

但多数情况下,我们的同步代码块不存在多么激烈的锁竞争,synch显得十分浪费,所以自JDK6对synchronized进行了优化,有了锁膨胀机制。

偏向锁:当某个线程获取锁时,先认为不存在锁竞争,在对象头中设置标记,标记当前对象已被该线程获取,若无其他线程参与的情况,则JVM不需要进行任何其他同步操作,若有其他线程尝试获取锁,则升级为轻量锁。

若程序中的锁总是被不同线程访问,那么偏向锁就是多余的。可能在某种情况下禁用偏向锁反而更提升性能。

轻量锁:进入同步代码块后,JVM会在当前线程栈帧中建立一个称为锁记录(Lock Record)的空间记录锁对象目前对象头MarkWord的信息,然后CAS操作将MarkWord更新为指向该LockRecord的指针。如果更新成功,那么标识当前线程持有了锁,如果更新失败且当前MarkWord指向的不是自己,那么表示锁在被两个以上的线程争抢,这时才膨胀为重量级锁。

下边是对象头MarkWord中的信息,写段程序来验证锁膨胀

 图来自https://www.csdn.net/tags/NtzaAg1sNjI5MzktYmxvZwO0O0OO0O0O.html

引入jar

        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
public class Test {

    public static void main(String[] args) throws InterruptedException, IOException {
        TimeUnit.SECONDS.sleep(5L);
        Object o = new Object();

        System.out.println("偏向锁,无偏向线程");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

        synchronized (o) {
            System.out.println("偏向锁,偏向当前线程");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o) {
                    System.out.println("新线程获取锁,锁升级为轻量锁");
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                }
            }
        }).start();

        // 等待上边线程执行完毕
        TimeUnit.SECONDS.sleep(5);
        System.out.println("轻量锁1执行完毕");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

        synchronized (o) {
            System.out.println("轻量锁2");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }

        System.out.println("多线程争夺锁,锁升级为重量锁");
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o) {
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                    try {
                        TimeUnit.SECONDS.sleep(5);
                    } catch (InterruptedException e) {}
                }
            }
        }).start();

        synchronized (o) {
            TimeUnit.SECONDS.sleep(1);
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }

        System.out.println();
    }
}

执行结果:(字节序为小端序)

新对象在执行同步块前无偏向线程,执行同步块时锁标识101,后边的则是指向当前线程

 当有其他线程尝试获取锁,锁升级为轻量,锁标识00,后边的数则指向栈帧

 同步执行完毕,对象头变为无锁状态001,指针清空

升级为重量级锁 ,锁标识为10,指针指向同一个monitor

全部:

偏向锁,无偏向线程
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 48 1e 03 (00000101 01001000 00011110 00000011) (52316165)
      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)                           28 f3 41 21 (00101000 11110011 01000001 00100001) (557970216)
      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执行完毕
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

轻量锁2
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           68 f3 14 03 (01101000 11110011 00010100 00000011) (51704680)
      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)                           9a 7d dc 1c (10011010 01111101 11011100 00011100) (484212122)
      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)                           9a 7d dc 1c (10011010 01111101 11011100 00011100) (484212122)
      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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值