首先介绍两个朋友,第一位是“佩奇”同学,非常乐于思考,经常提问题,第二位是“小智”同学,聪明绝顶,乐于解答问题。
java中线程的切换是线程从用户态(jvm层)到内核态(操作系统层)的转换,代价比较大。对于执行时间很短的任务,可能任务执行的时间还没有线程切换的时间长,为了这段时间去挂起和恢复线程非常不值得,如果通过自旋的方式(即尝试让当前线程空转,等待一段时间但不放弃处理器的执行时间)可以获取到锁,就可以避免线程的切换,从而减少并发的压力。
佩奇:为什么任务执行时间比较长的任务不适合使用自旋锁?
小智:自旋是通过循环的方式进行空转,对于任务执行比较长的任务,空转的这段时间就白白浪费了cpu资源。
由于无法确定任务具体执行的时间,空转次数也就无法确定,很难去确定一个准确的自旋周期,JDK1.6后引入了一个自适应自旋锁,图示如下:
① 当线程T1尝试获取锁时,发现已经被T2线程占用,就执行自旋。
② T1自旋了一段时间后获得了这把锁,就开始执行任务。
③ T3线程竞争锁时发现刚刚的T1线程通过自旋获得过锁,并且持有锁的线程正在执行(不一定是T1线程),那么就认为下次通过自旋的方式也可以获得锁,就会自旋更长的时间;如果自旋很少成功获得过,那么下次就会忽略掉自旋过程,以免浪费处理器资源。
有了自适应自旋,虚拟机对程序锁的状态预测就会越来越准确,虚拟机就会变得越来越“聪明”了。