当前位置:主页 > java教程 > Java锁擦除与锁粗化

Java锁擦除与锁粗化概念和使用详解

发布:2023-04-05 09:55:01 59


给网友朋友们带来一篇相关的编程文章,网友向兴为根据主题投稿了本篇教程内容,涉及到Java锁擦除与锁粗化、Java锁粗化、Java锁擦除、Java锁擦除与锁粗化相关内容,已被565网友关注,如果对知识点想更进一步了解可以在下方电子资料中获取。

Java锁擦除与锁粗化

一、什么是锁擦除

锁擦除是指虚拟机即时编译器(JIT)在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行擦除。锁擦除的主要判定依据来源于逃逸分析的数据支持,如果判断在一段代码中,堆上的所有数据都不会逃逸出去从而被其他线程访问到,那就可以把它们当做栈上数据对待,认为它们是线程私有的,同步加锁自然就无须进行。

二、锁擦除的演示

public class LockErasureDemo {
    public static void main(String[] args) {
        new Thread(() -> {
            String contact = contact("aa", "bb", "cc");
            System.out.println(Thread.currentThread().getName() + ":" + contact);
        }, "t1").start();
        new Thread(() -> {
            String contact = contact("dd", "ee", "ff");
            System.out.println(Thread.currentThread().getName() + ":" + contact);
        }, "t2").start();
    }
    private static String contact(String s1, String s2, String s3) {
        StringBuffer stringBuffer = new StringBuffer();
        return stringBuffer.append(s1).append(s2).append(s3).toString();
    }
}

观察上面的代码,我们都知道StringBuffer的append方法是加了synchronized的同步方法:

public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

这里锁住的对象其实就是stringBuffer这个局部变量,因为是局部变量,所以每个线程进来生成的stringBuffer对象不同,相当于每个线程自己new了一把锁,所以这里不存在竞争同一把锁的问题,JVM底层会将这个锁进行擦除。

三、什么是锁粗化

原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小,只在共享数据的实际作用域中才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。大部分情况下,上面的原则都是正确的,但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。

四、锁粗化的演示

public class LockCoarseningDemo {
    static Object objLock = new Object();
    public static void main(String[] args) {
        // 反复加锁、解锁
        new Thread(() -> {
            synchronized (objLock) {
                System.out.println("a");
            }
            synchronized (objLock) {
                System.out.println("b");
            }
            synchronized (objLock) {
                System.out.println("c");
            }
        }, "t1").start();
    }
}

观察上面的案例,同一个线程对同一把锁,反复不断地获取锁、释放锁,这样肯定影响性能。为了避免重复的加锁解锁,JVM可能会将上面的代码优化成下面这样:

// 锁粗化: 如果方法中首尾相接,前后相邻的都是同一个锁对象,那JIT编译器就会把这几个synchronized块合并成一个大块
// 加粗加大范围,一次申请锁即可,避免多次的申请和释放锁,提升性能
new Thread(() -> {
    synchronized (objLock) {
        System.out.println("a");
        System.out.println("b");
        System.out.println("c");
    }
}, "t1").start();

到此这篇关于Java锁擦除与锁粗化概念和使用详解的文章就介绍到这了,更多相关Java锁擦除与锁粗化内容请搜索码农之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持码农之家!


参考资料

相关文章

  • Java锁粗化与循环问题详解

    发布:2019-10-04

    这篇文章主要介绍了Java 锁粗化与循环的相关知识,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下


网友讨论