04.JDK对锁的更多优化措施
1.逃逸分析
如果jdk在分析编译的时候发现,一个对象不会逃逸方法外或者线程外,则可针对此变量进行优化:
在写代码的时候,即使方法加了synchronized关键字,编辑器也会把你这个方法的锁消除掉.
2.锁消除
虚拟机的运行时编译器在运行时如果检测到一些要求同步的代码上不可能发生共享数据竞争,则会去掉这些锁。
如果JVM检测到某段代码不可能存在共享数据竞争,JVM会对这段代码的同步锁进行锁消除。
在动态编译同步块的时候,JIT编译器可以借助一种被称为逃逸分析(Escape Analysis)的技术来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。
如果同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。
举例:
public void vectorTest() {
Vector<String> vector = new Vector<String>();
for (int i = 0; i < 10; i++) {
vector.add(i + "");
}
System.out.println(vector);
}
Vector的add方法是Synchronized修饰的。
在运行这段代码时,JVM可以明显检测到变量vector没有逃逸出方法vectorTest()之外,所以JVM可以大胆地将vector内部的加锁操作消除。
****以上的作用
消除无意义的锁获取和释放,可以提高程序运行性能。这也是说为什么说在使用锁的过程中,如果不是特别的业务需求(如中断获取锁,尝试获取锁),尽量使用synchronized关键字而不是显示锁,因为jdk在优化synchronized是下了非常大的功夫的.
3.锁粗化
将临近的代码块用同一个锁合并起来,就是jdk发现你一个方法两次加锁之间的执行代码非常非常的短,jdk会自动的把你这两次加锁合并成一次加锁.
很多时候,我们提倡尽量减小锁的粒度,可以避免不必要的阻塞。 让同步块的作用范围尽可能小,仅在共享数据的实际作用域中才进行同步,如果存在锁竞争,那么等待锁的线程也能尽快拿到锁。
但是如果在一段代码中连续的用同一个监视器锁反复的加锁解锁,甚至加锁操作出现在循环体中的时候,就会导致不必要的性能损耗,这种情况就需要锁粗化。
锁粗化就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁。
举例:
for(int i=0;i<100000;i++){
synchronized(this){
do();
}
会被粗化成:
synchronized(this){
for(int i=0;i<100000;i++){
do();
}
****以上的作用
消除无意义的锁获取和释放,可以提高程序运行性能。这也是说为什么说在使用锁的过程中,如果不是特别的业务需求(如中断获取锁,尝试获取锁),尽量使用synchronized关键字而不是显示锁,因为jdk在优化synchronized是下了非常大的功夫的.