锁消除
锁消除即删除不必要的加锁操作。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