锁优化

高效并发是从JDK1.5到JDK1.6的一个重要改进,如适应性自旋、锁消除、锁粗化、轻量级锁和偏向锁等技术。

13.3.1 自旋锁与自适应自旋

互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都会影响性能。而很多应用上共享数据的锁定状态只持续很短的时间,为了这段时间挂起和恢复线程很不值得,所以可以让后面请求锁的那个线程“稍等一下”,但是不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放锁,为了让线程等待,只需让线程执行一个忙循环(自旋),这就是自旋锁。

自旋等待不能代替阻塞,因为它虽然避免了线程切换的开销,但它是要占用处理器时间的,如果锁被占用的时间很短,自旋等待的效果就好,反之自旋线程就会白白消耗处理器资源。因此,自旋等待的时间必须要有限度,如果自旋超过了限定的次数仍然没有获得锁,就应当挂起线程。默认是10次,可通过参数-XX:PreBlockSpin来更改。

JDK1.6之后引入了自适应的自旋锁,这意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

13.3.2 锁消除

锁消除是指虚拟机即时编译器在运行时,在对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。

13.3.3 锁粗化

大多数情况下,总是推荐将同步块的作用范围限制得尽量小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。但是如果一系列操作都对同一个对象反复加锁和解锁,那么频繁的同步操作也会导致不必要的性能损耗。如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁,就会把加锁同步的范围扩展(粗化)到整个操作序列的外部。

13.3.4 轻量级锁

轻量级锁并不是用来代替重量级锁(传统的锁机制)的,它是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比重量级锁更慢。

13.3.5 偏向锁

偏向锁是JDK1.6中引入的,目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,偏向锁是在无竞争的情况下把整个同步消除掉,连CAS也不做了。

偏向锁的“偏”就是偏心的“偏”,意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。

偏向锁可以提高有同步但无竞争的程序性能。但它并不一定总对程序有利,如果程序中大多数的锁总是被多个不同的线程访问,那偏向锁就是多余的。

猜你喜欢

转载自my.oschina.net/u/3342874/blog/1809757