侧边栏壁纸
博主头像
xh博主等级

永远是一个学者

  • 累计撰写 15 篇文章
  • 累计创建 6 个标签
  • 累计收到 8 条评论
标签搜索

目 录CONTENT

文章目录

验证synchronized锁升级过程

xh
xh
2023-03-22 / 3 评论 / 3 点赞 / 648 阅读 / 1,217 字
温馨提示:
本文最后更新于 2024-06-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 理论

锁的状态分为四种:无锁状态、偏向锁、轻量级锁、重量级锁。

锁可以从偏向锁升级为轻量级锁,再升级为重量级锁,但锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。

锁的状态记录在对象头的Mark Word中,(锁的标志位看后几位bit位)如下:

image-20230322161640619

{tabs-pane 后三位 } 001 代表无锁状态
101 代表偏向锁 {/tabs-pane} {tabs-pane 后两位 } 00 代表轻量级锁
10 代表重量级锁 {/tabs-pane}

2. 代码验证

引入对象头分析工具

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

打印mark word

// 对象
Object object = new Object();

// 打印对象头mark word
System.out.println(ClassLayout.parseInstance(object).toPrintable());

对象内存区域,红框表示mark word信息

image-20230322111211667

// 打印出来的值(本人用的是windows系统运行,所以这里打印出来的值是小端模式)
00000001 00000000 00000000 00000000

// 转换(大端模式)
00000000 00000000 00000000 00000001

// object对象没有加锁,没有被synchronized修饰,对象头mark word后三位001为无锁状态

无锁 —> 偏向锁

开启偏向锁,当object对象被上锁,并有一个线程执行,object的mark word后三位标志位会升级为偏向锁(101)

代码执行前先配置jvm参数:【开启偏向锁】【关闭延迟开启偏向锁】

-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
public static void main(String[] args) throws InterruptedException {
    TimeUnit.SECONDS.sleep(5);
    Object object = new Object();
    System.out.println("============== 加锁前mark word ==============");
    System.out.println(ClassLayout.parseInstance(object).toPrintable());

    synchronized (object) {
        // 业务逻辑...
        System.out.println("============== 加锁后mark word ==============");
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
    }
}


image-20230322111211667

// ================ 加锁前mark word ================ (转大端模式后)
// 开启偏向锁,默认匿名偏向
00000000 00000000 00000000 00000101

// ================ 加锁后mark word ================ (转大端模式后)
// 偏向某个线程
11110001 10101110 11011000 00000101

偏向锁 —> 轻量级锁

当有两个,及两个以上的线程竞争锁不激烈的情况下(串行执行时),偏向锁会升级为轻量级锁

public static void main(String[] args) throws InterruptedException {
    TimeUnit.SECONDS.sleep(5);
    Object object = new Object();
    // 没有加锁前
    System.out.println("========== 加锁前打印的对象头 ==========");
    System.out.println(ClassLayout.parseInstance(object).toPrintable());

    // t1线程先进行加锁执行
    new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t1线程打印的对象头==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    }).start();

    // 等待500毫秒(模拟升级轻量级锁)(模拟竞争不激烈的情况下,t1线程执行完后,t2线程再进行执行)
    TimeUnit.MILLISECONDS.sleep(500);

    // t2线程再进行加锁执行
    new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t2线程打印的对象头 ==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    }).start();
}


image-20230322111211667

// ================ 加锁前打印的mark word ================ (转大端模式后)
00000000 00000000 00000000 00000101 // 匿名偏向

// ================ t1线程打印的mark word ================ (转大端模式后)
10001011 11000011 00000000 00000101 // 偏向锁

// ================ t2线程打印的mark word ================ (转大端模式后)
11100000 01101111 11110101 00010000 // 轻量级锁

重量级锁

当有多个线程竞争锁比较激烈的情况下(都想在同一时刻获取到锁),会直接升级为重量级锁

public static void main(String[] args) throws InterruptedException {
    TimeUnit.SECONDS.sleep(5);
    Object object = new Object();
    // 没有加锁前
    System.out.println("========== 加锁前打印的对象头 ==========");
    System.out.println(ClassLayout.parseInstance(object).toPrintable());


    // t1线程先进行加锁执行
    new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t1线程打印的对象头 ==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    }).start();

    // 等待500毫秒(模拟升级轻量级锁)(模拟竞争不激烈的情况下,t1线程执行完后,t2线程再进行执行)
    TimeUnit.MILLISECONDS.sleep(500);

    // t2线程再进行加锁执行
    new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t2线程打印的对象头 ==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    }).start();

    // 等待500毫秒,(开始模拟升级重量级锁)开始模拟竞争比较激烈的情况(同一时刻都t3、t4线程都想获取锁)
    Thread t3 = new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t3线程打印的对象头 ==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    });
    Thread t4 = new Thread(() -> {
        synchronized (object) {
            System.out.println("========== t4线程打印的对象头 ==========");
            System.out.println(ClassLayout.parseInstance(object).toPrintable());
        }
    });
    t3.start();
    t4.start();
}


image-20230322111211667

image-20230322111211667

// ================ 加锁前打印的mark word ================ (转大端模式后)
00000000 00000000 00000000 00000101 // 匿名偏向

// ================ t1线程打印的mark word ================ (转大端模式后)
00111010 00100001 10111000 00000101 // 偏向锁

// ================ t2线程打印的mark word ================ (转大端模式后)
11101001 10011111 11110000 00000000 // 轻量级锁

// ================ t4线程打印的mark word ================ (转大端模式后)
00110110 10100011 11010000 11101010 // 重量级锁

// ================ t3线程打印的mark word ================ (转大端模式后)
00110110 10100011 11010000 11101010 // 重量级锁
3

评论区