自旋锁
线程被阻塞后便进入内核Linux调度状态,这个会导致系统在用户态和内核态来回切换,严重影响锁的性能
缓解上述问题的办法便是自旋,其原理是:当发生争用时,若Owner线程能在很短的时间内释放锁,则那些正在用线程可以稍微等一等(自旋),在Owner线程释放锁后,争用线程可能会立即得到锁,从而便面了系统的阻塞。但Owner运行的时间可能会超出了临界值,争用线程自旋一段时间后还无法获得锁,这时争争用线程则会停止自旋进入阻塞状态(后退)。基本思路就是就是自旋,不成功再阻塞;尽量降低阻塞的可能性,这对那些执行时间很短的代码块来说有非常重要的性能提升。自旋锁有个贴切的名字,自旋指数后退锁,,也即复合锁,很显然,自璇在多个处理器上才有意义。
还有个问题是,线程自旋时做些啥?其实啥都不做,可以执行几次for循环,可以执行几条空的汇编指令,目的是占着cpu不放,等待获得锁的机会,所以说自旋是把双刃剑,如果旋的时间过长会影响整体性能,时间过短又达不到延迟阻塞的目的。显然,自选的周期选择显得非常重要,但这与操作系统,硬件体系、系统的负载等诸多场景相关,很难选择,如果选择不当,不但性能得不到提高,可能还会下降,因此大家普遍认为自旋锁不具备可扩展性。
偏向锁
偏向锁主要解决无竞争下的锁的性能问题??
现在几乎所有的锁都是可重入的,也即已经获得锁的线程可以多次锁住/解锁监视对象,按照之前的hotspot设计,每次加锁/解锁都会涉及到一些CAS操作(比如对于等待队列的CAS操作),CAS操作会延迟本地调用,因此偏向锁的想法是一旦线程第一次获得监视对象,之后让监视对象偏向这个线程,之后的多次调用则可以避免CAS操作,说白了就是置一个变量,如果发现为true则无需再更重加锁/解锁的流程。
CAS和SMP架构
CAS为什么会引入本地延迟?这里从SMP对称多处理器架构说起,下面大概说明了SMP的结构:
其意思是所有的CPU会共享一条系统总线BUS,靠此总线连接主存,每个核都有自己的一级缓存,各核相对于BUS对称分布,因此这种解雇称为对称多处理器
CAS的全称为Compare and swap,一条CPU的原子指令,器作用是让CPU比较后原子地更新某个位置的值,经过调查发现,其实现方式基于硬件平台的汇编指令,就是说CAS是靠硬件实现的,JVM只是封装了汇编调用,那些AtomicInteger类便是使用了这些封装后的接口
cache一致性考验,当很多线程共享一个对象的情况下,即物理层面是很多cpu核通过总线修改对象内存的数据,那么总线的通信能力将成为瓶颈,总线引起的总线风暴,这就是所谓的本地延迟,本质上偏向锁就是为了消除CAS,降低Cache一致性流量
synchronzed的底层实现主要依靠Lock-Free的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,获得了高吞吐。
网友评论