Java锁之偏向级锁、轻量级锁、重量级锁
# Java锁之偏向级锁、轻量级锁、重量级锁
原文链接:(30条消息) Java锁之偏向级锁、轻量级锁、重量级锁_Colourful.的博客-CSDN博客_偏向级锁 (opens new window)
# 文章目录
- 什么是偏向级锁、轻量锁、重量级锁 (opens new window)
- 偏向级锁 (opens new window)
- 轻量级锁 (opens new window)
- 重量级锁 (opens new window)
# 什么是偏向级锁、轻量锁、重量级锁
首先,我们需要明确一点:**这三种锁只针对synchronized**
我们都知道,任意一个java对象都可以做为锁,java对象的锁信息存储在对象头中的Mark Word字段中。Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。32位JVM的Mark Word的默认存储结构如下图:
Java中锁主要存在四种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,随着竞争的激烈而逐渐升级。锁只能升级而不能降级,即一个锁从偏向级锁升级到轻量锁时,不能再重新回到偏向级锁。
# 偏向级锁
顾名思义,偏向某一个线程,当线程数目不多的时候,由于反复获取锁会使得我们的运行效率下降,于是出现了偏向级锁。JVM使用CAS操作把线程ID记录到对象的Mark Word当中,并修改标识位,name当前线程就拥有了这把锁。
偏向级锁不需要操作系统的介入,JVM使用CAS操作将线程ID放入对象的Mark Word字段中,于是线程获得了锁,可以执行synchronized代码块的内容,当线程再次执行到这个synchronized的时候,JVM通过锁对象的Mark Word判断 :当前线程ID还存在,还持有这个对象的锁,于是就可以继续进入临界区执行,而不需要再次获得锁
偏向锁,在没有别的线程竞争的时候,一直偏向当前线程,当前线程就可以一直进入synchronized修饰的代码块一直运行。
如果在运行中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会消除它身上的偏向锁,将锁升级到轻量级锁。
**总结一点**:偏向级锁就是为了消除资源无竞争情况下的同步原语,进一步提高了程序的运行性能。
# 轻量级锁
轻量级锁是由偏向级锁升级来的,当一个线程运行同步代码块时,另一个线程也加入想要运行这个同步代码块时,偏向锁就会升级为轻量级锁。
首先,JVM会将锁对象的Mark Word恢复成为无锁状态,**在当前两线程的栈桢中各自分配一个空间,叫做Lock Record,把锁对象account的Mark Word在两线程的栈桢中各自复制了一份,官方称为:Displaced Mark Word**
然后一个线程尝试使用CAS将对象头中的Mak Word替换为指向锁记录的指针,如果替换成功,则当前线程获得锁,如果失败,则当前线程**自旋**重新尝试获取锁。当自旋获取锁仍然失败时,表示存在其他线程竞争锁(两个或两个以上线程竞争同一个锁),**则轻量级锁会膨胀成重量级锁**
举个例子: 线程A、线程B同时想要执行一个同步代码块,假设线程A抢到了锁,则线程A的Lock Record的地址 会被CAS操作放到了锁对象Mark Word中,并且将锁标志位改为00,这意味着线程A就获取到了该锁,可以执行同步代码块。
而线程B没有抢到锁,但是**线程B不会阻塞,而是通过自旋的方式,等待获取锁。(一般默认自旋10次)**,如果线程A释放掉锁,则将线程A中的Displaced mark word使用CAS复制回锁对象的Mark Word字段,此时线程B就可以获取锁对象,如果线程B还没有获取成功,则说明同时存在两个或两个以上的线程同时竞争这一把锁,**轻量级锁会升级成为重量级锁**。
# 重量级锁
我们上面提到,当多个线程竞争同一个锁时,会导致除锁的拥有者外,其余线程都会自旋,这将导致自旋次数过多,cpu效率下降,所以会将锁升级为重量级锁。
**重量级锁需要操作系统的介入,依赖操作系统底层的Muptex Lock**。JVM会创建一个monitor对象,把这个对象的地址更新到Mark Word中。
**当一个线程获取了该锁后,其余线程想要获取锁,必须等到这个线程释放锁后才可能获取到,没有获取到锁的线程,就进入了阻塞状态。**
编辑 (opens new window)
上次更新: 2024/01/26, 05:03:22
- 01
- python使用生成器读取大文件-500g09-24
- 02
- Windows环境下 Docker Desktop 安装 Nginx04-10
- 03
- 使用nginx部署多个前端项目(三种方式)04-10