作用范围
方法
静态方法
使用的同步锁是类对象,和其他静态同步方法存在锁竞争
非静态方法
使用的锁是当前对象,同一对象之间存在锁竞争,不同对象之间不存在竞争关系
代码块
使用的锁是synchronized中传入的对象,依据是否同一对象而决定否存在竞争
底层原理
方法
代码块
每个java对象的对象头中都有monitor对象,通过能否获取到monitor对象来判断能否获取锁
锁优化
自旋锁
当线程竞争锁失败时,不直接阻塞自己,而是自旋(空等待,比如一个有限的for循环)一会儿,在自旋的同时重新竞争锁。如果在自旋结束前获得了锁,那么获取锁成功;否则自旋结束后阻塞自己
自旋锁可以减少线程阻塞造成的线程切换(包括挂起线程和恢复线程)
<ol><li>单核处理器情况下,不存在实际的并行。当前线程不阻塞自己,拥有锁的线程就无法执行,锁永远不会释放。进而,如果线程多而处理器少,自旋也会造成不少无谓的浪费<br></li><li>自旋锁要占用CPU,如果是计算密集型任务,这一优化通常得不偿失,减少锁的使用是更好的选择</li><li>如果锁竞争时间比较长,那么自旋通常不能获得锁,白白浪费自旋占用的CPU时间。这通常发生在所持有时间长,且竞争激烈的场景中,此时应主动禁用自旋锁</li></ol>
使用-XX:-UseSpinning参数关闭自旋锁优化;-XX:PreBlockSpin参数修改默认的自旋次数。<br>
偏向锁
偏向锁的目标是减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗
如果有其他线程申请锁,那么偏向锁很快就膨胀为轻量级锁。浪费了维持偏向锁的性能消耗
使用参数-XX:-UseBiasedLocking禁止偏向锁优化(默认打开)。
轻量级锁
使用轻量级锁时,不需要申请互斥量,仅仅将Mark Word中的部分字节CAS更新指向线程栈中的Lock Record,如果更新成功,则轻量级锁获取成功。否则可以继续使用自旋锁获取或者升级为重量级锁
轻量级锁的目标是减少无实际竞争的情况下,使用重量级锁产生的性能消耗
如果锁竞争激烈,轻量级锁很快就将升级为重量级锁,那么维持轻量级锁的过程就成了浪费
重量级锁
内置锁在Java中被抽象成监视器锁(monitor)。监视器锁直接对应底层操作系统的互斥量(mutex)
这种同步方式成本非常高,包括系统调用引起的内核态和用户态切换、线程阻塞造成的线程切换等