自旋锁与自适应自旋

Posted dituicyqz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自旋锁与自适应自旋相关的知识,希望对你有一定的参考价值。

上一节讨论同步锁提到,等待锁的线程进入阻塞状态是需要从用户态切换到内核态,这种操作会给系统的并发带来非常大的压力。于是,在有多个处理器的情况下,我们乐观的认为 “等一下”,不放弃处理器时间,或许持有锁的线程很快就会释放锁。为了让线程等待,需要让线程执行一个忙循环(while(true)),这项技术就叫做自旋

自旋锁解决的问题就是:避免用户线程和内核切换的消耗

但线程自旋是需要消耗cpu的,如果一直获取不到锁,那线程也不能一直占用cpu自旋做无用功,所以需要设定一个自旋等待的最大时间。 如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。

自旋锁的优缺点:自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗,阻塞挂起再唤醒这些操作会导致线程发生两次上下文切换!

但是如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,线程占用cpu自旋的消耗大于线程阻塞挂起操作的消耗,其它需要cpu的线程又不能获取到cpu,造成cpu的浪费,所以这种情况下我们要关闭自旋锁。

2、JVM对于自旋周期的选择,jdk1.5这个限度是一定的写死的,在1.6引入了适应性自旋锁,适应性自旋锁意味着自旋的时间不再是固定的了,而是由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行当中,那么虚拟机认为这次也有可能再次成功,进而允许它自旋时间更久一点,比如100个循环。相反,如果对于某个锁,自旋很少成功过 ,那么会忽略自旋过程直接进入阻塞,以免造成cpu浪费。

自旋锁的开启 JDK1.6中-XX:+UseSpinning开启;

-XX:PreBlockSpin=10 为自旋次数;

JDK1.7后,去掉此参数,由jvm控制;

以上是关于自旋锁与自适应自旋的主要内容,如果未能解决你的问题,请参考以下文章

JVM锁优化

从synchronized入手看锁

从synchronized入手看锁

从synchronized入手看锁

Java内存模型JMM,虚拟机线程实现

JAVA并发之锁获取步骤及锁优化