Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

README.md

对象锁

每一个 Object 都有一个隐含的锁,也称作监视器对象。
在同步的时候是获取对象的 monitor,即获取到对象的锁。
在JDK1.6之前,synchronized是一个重量级锁,性能比较差。从JDK1.6开始,
为了减少获得锁和释放锁带来的性能消耗,synchronized进行了优化,引入了 偏向锁和 轻量级锁的概念。

这几个状态会随着锁竞争的情况逐步升级。
为了提高获得锁和释放锁的效率,锁可以升级但是不能降级。
  • 锁标志位
锁标识 lock=00 表示轻量级锁
锁标识 lock=10 表示重量级锁
偏向锁标识 biased_lock=1表示偏向锁
偏向锁标识 biased_lock=0且锁标识=01表示无锁状态

状态

  • 无锁状态

  • 偏向锁(Biased Lock)

大多数情况下,锁不仅不存在多线程竞争 而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

偏向锁可以通过 -XX:+UseBiasedLocking开启或者关闭

偏向锁的获取 偏向锁的获取过程非常简单,当一个线程访问同步块获取锁时, 会在对象头和栈帧中的锁记录里存储偏向锁的线程ID,表示哪个线程获得了偏向锁

偏向锁的撤销 当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放偏向锁, 撤销偏向锁的过程需要等待一个全局安全点(所有工作线程都停止字节码的执行

  • 轻量级锁(Lightweight Lock)

偏向锁撤销以后对象会可能会处于两种状态 一种是不可偏向的无锁状态, 简单来说就是已经获得偏向锁的线程已经退出了同步代码块,那么这个时候会撤销偏向锁,并升级为轻量级锁 一种是不可偏向的已锁状态, 简单来说就是已经获得偏向锁的线程正在执行同步代码块,那么这个时候会升级到轻量级锁并且被原持有锁的线程获得锁

  • 重量级锁(Heavyweight Lock)

重量级锁依赖对象内部的monitor锁来实现,而monitor又依赖操作系统的MutexLock(互斥锁)

为什么重量级锁的开销比较大呢?

原因是当系统检查到是重量级锁之后,会把等待想要获取锁的线程阻塞,被阻塞的线程不会消耗CPU, 但是阻塞或者唤醒一个线程,都需要通过操作系统来实现, 也就是相当于从用户态转化到内核态,而转化状态是需要消耗时间的