自旋锁 VS 适应性自旋锁
堵塞或者notify一个Java线程需要操作系统切换CPU状态来完成(详情请参考11408)。这种状态切换需要耗费CPU时间。如果同步代码块种的内容过于简单。状态切换消耗的时间可能比用户代码执行的时间还要长。
在许多场景中,同步资源的锁定时间很短,为了这一段时间去切换线程,线程挂起和恢复现场的花费可能会让系统得不偿失。如果机器有多个CPU,能够让两个或以上的线程同时并行执行,就可以让后面那个请求锁的线程不放弃CPU的执行时间,看看持有锁的线程是否很快释放锁。
为了让当前线程"等一下" 我们需让当前线程进行自旋,如果在自旋完成后前面同步资源已经释放了锁。那么当前线程就可以不必堵塞而是直接获取同步资源。避免线程切换的开销。这就是自旋
自旋锁本身就有缺点。他不能代替堵塞。自旋等待虽然避免了线程切换的开销,但是他要占用CPU时间。如果锁被占用的时间很短。自旋等待的效果就会比较好。反之,如果锁被占用的时间很长。那么自旋的线程只会白白浪费CPU资源。所以 自旋等待的时间必须要有一定的限制。如果自旋超过一定的次数(JDK默认10次 参数PreBlockSpin)没有成功获得锁 就应该suspend
自旋锁的实现原理同样也是CAS。AtomicInteger中调用unsafe进行自增操作的源码中的do-while循环就是一个自旋操作。如果修改数值失败则通过循环来执行自旋。知道修改成功
public final