锁消除

/ 多线程 / 没有评论 / 357浏览

锁消除的意思是说虚拟机在运行时,虽然代码进行了同步,但是如果虚拟机检测到不存在数据竞争时,虚拟机就会自动把锁进行消除。锁消除主要的判定依据是如果堆上的所有数据都不会被其它的线程访问到,那么就可以理解为这些数据是线程私有的。既然是线程私有的,那么同步加锁也就没有存在的必要了,于是虚拟机就会将锁消除掉。我们看一下下面具体的代码来实际验证一下锁消除的实际应用。

public class Test {
public String concatString(String s1, String s2, String s3) {
return s1 + s2 + s3;
}
}

 上述代码中我们并没有添加任何同步方法。并且我们知道String是一个不可变的类,无论我们怎么操作底层的实现方式,都是会生成一个新的String来处理。所以上述代码在编译后会被优化。我们使用javac命令来查看一下编译后的代码是。

public class Test {
public String concatString(String s1, String s2, String s3) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
sb.append(s3);
return sb.toString();
}
}

看完编译器优化后的代码,我们发现此时的代码已经无形中添加了同步方法。原因就是在append()方法的底层,实际就是一个synchronized类型的同步方法。我们看一下append()方法的源码如下。

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

源码中显示append()方法确实是一个同步方法,按照同步方法的规则,同步方法的锁就是当前对象也就是StringBuffer对象。虚拟机执行时发现同步方法锁的动态作用域是在concatString()方法的内部。 也就是说其他线程无法访问到它,所以虽然方法是同步方法也就是添加了锁,但是虚拟机在执行时可以将锁消除掉,所以代码编译后,虚拟机执行上述代码时,就会忽略所有的同步而直接执行。