【深入理解Java虚拟机】Java虚拟机内部实现的锁优化

高效并发是从JDK1.5到JDK1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本花费了大量的精力去实现各种锁优化技术。

自旋锁和自适应锁

自旋等待不能代替阻塞,且先不说对处理器的要求,自旋等待本身虽然避免了线程切换的开销,但它是要占用处理器时间的,因此,如果锁占用的时间很短,自旋等待的效果会非常好,反之,如果锁被占用的时间很长,那么自旋的线程只会白白消耗处理器资源,而不会做任何有用的工作。因此,自旋等待的时间必须要有一定的限度,如果自旋超过了限定的次数仍然没有成功获得锁,就应当使用传统的方式挂起线程了。
在JDK1.6有了自适应锁,自适应意味着自旋的时间不在固定了,而是由前一次的同一个锁上的自旋时间及锁的拥有者的状态来决定。随着程序运行和性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越准确。

锁消除

锁消除是指虚拟机JIT编译器运行时, 对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。锁消除的主要判断依据是逃逸分析的数据支持,如果判断一段代码中,堆上所有数据都不会逃逸出去从而被其他线程访问到,那么就可以把它们当做堆上数据对待,认为它们是线程私有的,同步加锁自然无须进行。

锁粗化

原则上,编写代码时,总是推荐奖同步块的作用范围限制到尽量小,只在共享数据的实际作用域中才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作出现在循环体内,那即是没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能耗损。
如果虚拟机检测到有这样一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展(粗化)到整个操作序列的外部,这就是锁粗化。

轻量级锁

在代码进入同步时,如果此同步对象没有被锁定,虚拟机首先将在当前线程的栈帧中建立名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,然后虚拟机将使用CAS操作尝试将对象的Mark Word更小为指向Lock Record的指针。如果这个更新成功了,则线程就拥有了这个对象的锁(轻量级锁),
如果更新失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果只说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程抢占了。如果两条以上的线程竞争同一个锁,那么轻量级锁就不在有效,要膨胀为重量级锁。

偏向锁

偏向锁的目的是为了消除数据在无竞争的情况下产生的同步问题。
如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那么偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页