引言
我们都知道高效并发是从JDK5升级到JDK6后一项重要的改进型,HotSpot虚拟机开发团队在这个版本上花费了大量的资源去实现各种锁优化技术,如适应性自旋(Adaptive Spinning)、锁消除(Lock Elimination)、锁膨胀(Lock Coarsening)、轻量级锁(Lightweight/Thin Locking)、偏向锁(Biased Locking)等等,这些技术都是为了在线程之间更高效地共享数据及解决竞争问题,从而提高程序的执行效率。我们也知道可重入锁(ReentrantLock)底层是使用CAS及队列实现的,那么可重入锁是轻量级锁么?要回答这个问题,首先让我们来回顾一下以上各种锁优化技术。
锁优化技术
内置锁是JVM提供的最便捷的线程同步工具,在代码块或者方法声明上添加synchronized
关键字即可使用内置锁。内置锁被抽象成监视器锁(monitor),在JDK6之前监视器锁可以认为直接对应底层操作系统中的互斥量(mutex)。这种同步方式的成本非常高,挂起线程和恢复线程的操作都需要转入内核态中完成。因此,这种锁也被叫做重量级锁(heavyweight lock)。
自旋锁
内核态与用户态的切换上不容易优化,同时,虚拟机的开发团队也注意到在许多应用上,共享数据的锁定状态只会持续很短的一段时间。那么我们是不是可以让后面请求锁的线程稍微等一下呢?也就是说让后面请求锁的线程不放弃处理器的执行时间,执行一个忙循环(自旋),看看持有锁的线程是否很快就会释放锁,如果还是没有能获得锁时再来阻塞自己,这项技术就是所谓的自旋锁。通过自旋锁可以减少线程阻塞造成的线程切换。可以使用-XX:+UseSpinning
参数开启自旋锁优化(默认是开启的),-XX:PreBlockSpin
参数来修改默认的自旋次数。
缺点
- 单核处理器上,不存在实际的并行,不管自旋多久都是浪费;进而,如果线程多而处理器少,自旋也会造成不少无谓的浪费。
- 自旋要占用CPU