锁优化
为了在线程之间更高效地共享数据,解决竞争问题,从而提高程序的执行效率,实现了多种锁优化技术。
自旋锁与自适应自旋
互斥同步对性能最大的影响:阻塞的实现,挂起和恢复线程的操作都需要转入内核态中完成。由于在很多时候,共享数据的锁定状态只会持续很短的时间,为了这段时间去进行挂起和恢复线程并不值得。因此可以考虑:当物理机有多个处理器,可以多次并行执行多个线程,此时可以让后面请求锁的线程稍等一会儿,但不放弃处理器的执行时间,看看持有锁的线程是否很快释放锁。为了让线程等待,会让线程执行一个忙循环(自旋)。
自旋锁:如果锁被占用的时间比较短,自旋等待的效果很好,避免了线程切换的开销。如果锁占用时间很长,自旋只会白白消耗处理器资源,因此自旋等待的时间会有一个限度。一般自旋次数 默认是 10次。自旋等待不能代替阻塞,主要原因是 虽然避免了线程切换的开销,但是需要占用处理器的执行时间。
自适应自旋:自适应表示 自旋的时间不固定,而是由 前一次在同一个锁上的 自旋时间 及 锁的拥有者状态 来决定。
锁消除
对于一些代码要求同步,但被检测不可能存在共享数据竞争。此时会将同步锁移除。
锁粗化
原则上:总是要求 同步块的作用范围尽可能的小。这样是使得 需要同步的操作数量尽可能变小,如果存在锁竞争,等待锁的线程也能尽快的拿到锁。
如果虚拟机检测到有一连串的操作 都是对同一个对象加锁,那么会将加锁同步的范围扩展到(粗化)到整个操作序列的外部。
轻量级锁
在没有多线程竞争的前提下,轻量级锁使用CAS操作,来避免使用互斥量的开销。但是 若存在锁的竞争,此时不光有 互斥量的开销,还额外增加了CAS操作,因此在有竞争的情况下,轻量级锁会比重量级锁执行效率更慢。
偏向锁
轻量级锁 是 在没有多线程竞争的前提下,使用CAS操作,来避免使用互斥量的开销。偏向锁 是在无竞争的情况下,将整个同步消除掉,连CAS操作都不做了。
当锁对象第一次被线程获取时,虚拟机会把对象的头的标志位设置为:01,即偏向模式。只要有另外的线程去产生获取这个锁,那么偏向模式就宣告结束。
偏向锁可以提高带有同步但无竞争的程序的性能。但是 它并不是总是对程序有利,如果程序中大多数的锁总是被多个不同的线程访问,那么偏向模式就是多余的。