JVM的锁优化-锁升级

发布时间 2023-10-10 11:17:50作者: 之士咖啡

锁升级

  锁升级,是JDK1.8版本中对于synchronized的优化。调查发现一般情况下锁的使用都是为了处理一些极端情况,但多时间,并不会出现并发争强的情况,直接是有synchronized比较重,会影响系统性能。
  升级步骤: 无锁 -> 偏向锁/匿名偏向锁 -> 轻量级锁 -> 重量级锁
  升级特点:一旦升级,无法降级
锁状态对照表:(根据下图,可查对锁状态)
image

无锁

所有对象最初都是无锁状态。

public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

image

偏向锁与轻量级锁

轻量级锁

  当第一线程获取到锁后,锁状态由无锁转为偏向锁。但实际发现锁状态是轻量级锁似乎没有偏向锁。~?!
  这其中涉及到jvm的偏向锁开启机制,5秒开始。5秒内,锁状态会由无锁转为轻量级锁。

    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
		// 获取锁
		// 此时锁,却是轻量级锁
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }

此时是轻量级锁
image

偏向锁

   添加5秒睡眠后,会出现偏向锁。此时会发现,偏向锁分为两钟,一个普通偏向锁,一个是匿名偏向锁。
  需要注意的是,当jvm开启偏向锁后,所有对象锁状态会自动转为匿名偏向锁,只会变更锁状态,不会记录线程信息。

    public static void main(String[] args) throws InterruptedException {
        // 5秒睡眠
        Thread.sleep(6000);
        Object o = new Object();
        // 此时锁为 匿名偏向级锁。即便是没有使用synchronized
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        // 此时锁为 偏向级锁
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }

image

重量级锁

  当轻量级锁进行CAS,当自旋达到一定次数后,锁升级为重量级锁。

    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        Object o = new Object();
        // 此时锁是 匿名偏向锁
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

        new Thread(() -> {
            // 线程拿到锁后,锁状态变为偏向级锁
            synchronized (o) {
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }).start();

        // 尝试获取锁后,发现是锁已经被获取,已是偏向级锁
        // 之后升级为 自旋锁,然后cas 一定次数后,升级为重量级锁
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
            // 如果cpu好的话,此时输出可能是轻量级锁
        }
    }

image



5秒开始偏向锁设定原因

  偏向锁转化为轻量级锁时,会涉及到偏向锁撤销操作。查看ClassLoader源码发现,但在大量并发加载class的情况下,锁撤销会影响性能。为了避免添加了5秒开启,让锁状态直接从无锁转化为轻量级锁。


对象头信息参考图

image