Java锁消除和锁粗化

锁消除

锁消除即删除不必要的加锁操作。JVM在运行时,对一些“在代码上要求同步,但是被检测到不可能存在共享数据竞争情况”的锁进行消除。根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程,那么就可以认为这段代码是线程安全的,无需加锁。

下面代码示例:

public class LockClearTest {
 
    public static void main(String[] args) {
        LockClearTest test = new LockClearTest();
 
        for (int i = 0; i < 100000; i++) {
            test.append("aaa", "bbb");
        }
    }
 
    public void append(String str1, String str2) {
   
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(str1).append(str2);
    }
复制代码

StringBuffer的append代码如下:

     @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
复制代码

从上述代码看出来,StringBuffer的append是个同步方法,但是LockClearTest中的 StringBuffer 属于一个局部变量,不可能从该方法中逃逸出去(即stringBuffer的引用没有传递到该方法外,不会被其他线程引用),因此其实这过程是线程安全的,可以将锁消除。

锁粗化

假设一系列的连续操作都会对同一个对象反复加锁及解锁,甚至加锁操作是出现在循环体中的,即使没有出现线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。

如果JVM检测到有一连串零碎的操作都是对同一对象的加锁,将会扩大加锁同步的范围(即锁粗化)到整个操作序列的外部。

下面代码示例:

public class StringBufferTest {
 
    StringBuffer stringBuffer = new StringBuffer();
 
    public void append(){
        stringBuffer.append("a").append("b").append("c");
    }
复制代码

上述代码每次调用 stringBuffer.append 方法都需要加锁和解锁,如果JVM检测到有一连串的对同一个对象加锁和解锁的操作,就会将其合并成一次范围更大的加锁和解锁操作,即在第一次append方法时进行加锁,最后一次append方法结束后进行解锁。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享