高效并发是JDK5升级到JDK6之后的一项重要改进。
1、自旋锁与自适应自旋
讨论互斥同步的时候,我们说到了互斥同步里对性能最大的影响就是阻塞,因为会不断地在用户态和内核态之间切换。而假如我们的物理机的CPU是双核及以上的处理器,可以同时让多个线程并行执行,那么我们就可以让后面请求锁的线程“等待一会儿”,但不放弃处理器的执行时间,看看是否有线程释放锁。
为了让线程等待,我们设置一个忙循环(自旋),这就是自旋锁。
自选等待不能代替阻塞,自旋等待本身虽然避免了线程切换的开销,但它是要占用处理器时间的。如果在短时间内另一个线程释放了锁,那么效果就会很好;反之长时间都获取不到锁,那么就会白白浪费CPU的运行时间。
因此,自旋等待必须有一定的限度,如果自旋次数超过了限定的次数仍然没有获取到锁,就应该用传统方式去挂起线程。自旋默认次数是10次,可以使用参数-XX:PreBlockSpin修改。
但对于JDK6来讲,对于自旋锁引入了自适应自旋,于是自旋的次数就不是固定的了。例如对于同一个锁对象,自旋等待刚刚获得过这个锁,并且持有锁的线程正在运行中,那么虚拟机认为这次自旋也很有可能再成功,进而允许自旋相对更长的时间;但对于这个锁自旋很少成功获得锁的话,就可能直接忽略自旋过程,避免浪费处理器资源。
2、锁消除
锁消除是指虚拟机在即时编译器在运行时检测到某段需要同步的代码不可能存在共享数据竞争,而实施对锁进行消除的优化策略。
锁消除的主要判定依据是逃逸分析技术(to be waited)
3、锁粗化
在编写代码的时候,我们对需要同步操作的代码块进行同步,都是尽量在共享数据的实际作用域中进行。但如果一系列的连续操作都对同一个对象反复加锁和解锁,即使没有线程竞争,频繁地进行互斥同步也会导致不必要的损耗。
例如下面一段代码,虚拟机就会把加锁范围扩大(粗化)到整个操作序列外部。

本文介绍了JDK锁优化的几种策略,包括自旋锁与自适应自旋、锁消除、锁粗化、轻量级锁和偏向锁。自旋锁减少了线程上下文切换的开销,锁消除是通过逃逸分析判断无需同步的代码,锁粗化则将连续的同步操作合并。轻量级锁和偏向锁在无竞争情况下提供了更高的效率,但当竞争发生时会升级为重量级锁。
最低0.47元/天 解锁文章
163

被折叠的 条评论
为什么被折叠?



