01 锁消除(同步省略)
是jvm对synchronized锁的优化
如果JVM检测到某段代码不可能存在共享数据竞争,JVM会对这段代码的同步锁进行锁消除
在动态编译同步块时,JIT编译器可以借助逃逸分析(Escape Analysis)技术来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程,若同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。
开启锁消除 -XX:+EliminateLocks,jdk8默认是开启的
02 举例
Vector的add()是Synchronized修饰的。
在运行这段代码时,JVM检测到变量vector没有逃逸出方法vectorTest()之外,JVM可以大胆地将vector内部的加锁操作消除。
public void vectorTest() {
Vector<String> vector = new Vector<String>();
for (int i =0; i <10; i++) {
vector.add(i +"");
}
System.out.println(vector);
}
public void test() {
Object object = new Object();
synchronized (object) {
System.out.println("----");
}
}
代码中object对象进行加锁,但object对象的生命周期只在test()中 ,不会被其他线程所访问到,所以在JIT编译阶段就会被优化成下面这种
public void test() {
Object object = new Object();
System.out.println("----");
}
01 锁粗化
是jvm对synchronized锁的优化
很多时候,我们提倡尽量减小锁的粒度,可以避免不必要的阻塞,让同步块的作用范围尽可能小,仅在共享数据的实际作用域中才进行同步,如果存在锁竞争,那么等待锁的线程也能尽快拿到锁。
若虚拟机检测到一段代码中连续的用同一个监视器锁反复的加锁解锁,甚至加锁操作出现在循环体中时,就会导致不必要的性能损耗,这种情况就需要锁粗化
锁粗化就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁。
for(int i=0;i<100000;i++) {
synchronized(this) {
do();
}
会被粗化成:
synchronized(this) {
for(int i=0;i<100000;i++){
do();
}
测试
默认是开启逃逸分析和锁化的,可以关闭锁粗化和开启锁粗化的时间差异
-server -XX:+DoEscapeAnalisis -XX:+EliminateLock 开启逃逸分析和开启锁粗化和锁消除
-server -XX:-DoEscapeAnalisis -XX:-EliminateLock 关闭逃逸分析和关闭锁粗化和锁消除