JAVA中synchronized与锁升级

好久没有更新博客了,今天来写一写JAVA中多线程中的一个小知识点synchronized与锁升级

权当是记一下笔记,以后自己忘记了可以看一下复习一下。

synchronized关键字出现在程序涉及到多线程时,使用synchronized关键字进行加锁

但是synchronized内部是怎么实现的呢,得一点点来剖析。

synchronized在 JDK 1.6 之前使用的是重量级锁,所谓重量级锁即是指使用操作系统OS提供的锁进行管控

然而由于直接采用重量级锁的代价太大,而程序往往并不需要这么重量级别的锁就可以完成任务,重量级锁反而使得程序的效率降低了

因此在之后的JDK版本中对其进行了改进,这里详细说一说现在采用的方式(这里默认以ORACLE的JVM —— hotspot 进行阐述)

synchronized 关键字处理逻辑时候,JVM默认开启了偏向锁,

所谓偏向锁是指,在markword中使用2个bit锁标志位(01)和1个1bit的偏向锁位标记的,出了所标志位和偏向锁位之外,

markword中此时还纪录了当前线程的指针 JavaThread 用于区分不同线程

若没有产生争抢的情况下,保持偏向锁状态直到结束。

若产生争抢,则进行锁状态的升级,将偏向锁升级为轻量级锁(自旋锁),其实现原理为

使用2bit的锁标志位(00)来代表,mardword中使用62位保存指向线程栈中Lock Record的指针

此时采用的方式为自旋锁,所谓自旋锁,即为进行循环,默认循环10次若另一线程还未释放锁,则进行进一步锁升级

此时,锁升级为重量级锁,即操作系统OS提供的锁,在markword中使用2bit锁标志位(10)指代

并在markword中使用62位纪录只想互斥量的指针

重量级锁本质上为采用汇编指令

1
lock cmpxchg 指令

lock 用于在多核CPU中,采用lock指令时,其他CPU核心禁止对该值进行修改

cmpxchg 即为采用CAS的方式修改变量值

所谓CAS即为Compare and Swap,翻译为比较并交换,若内存中值不为目标值,则将内存中的值修改为目标值

对象的markword中除了
01 偏向锁(也有人将此状态称之为 无锁)    
00 轻量锁     
10 重量锁    
之外还有一个2bit的锁标志位
11 GC废弃

从markword中也可以轻松看出 synchronized 的锁升级方式为

偏向锁 → 轻量锁 → 重量锁