一、Synchronized锁定对象
-
作用于普通方法,锁住的是当前对象。
-
作用于静态方法,锁住的是Class对象。
-
作用于同步块,锁住的是()中的对象。
二、Synchronized实现原理
-
JVM中对象内存布局:对象头信息、对象实际数据、对齐填充信息。
-
对象头又包括:MarkWord、klass、数组长度。
-
MarkWord:hashcode、GC分代年龄、锁状态标志、偏向线程ID、偏向时间戳。
-
klass:指向类元数据的指针。
-
数组长度:只有数组有。
-
所以Synchroinzed锁状态标识存在于 堆内存->对象头->MarkWord中 。
| 锁状态标志 | 存储内容 | 锁标志位 |
|---|---|---|
| 无锁 | 对象的hashCode、对象分代年龄、是否是偏向锁(0) | 01 |
| 偏向锁 | 偏向线程ID、偏向时间戳、对象分代年龄、是否是偏向锁(1) | 01 |
| 轻量级锁 | 指向栈中锁记录的指针 | 00 |
| 重量级锁 | 指向互斥量(重量级锁)的指针 | 10 |
我们可以看到,synchronized通过JVM实现,其中synchronized又有多个类型的锁,除了重量级锁是通过ObjectMonitor对象监视器(操作系统mutex互斥原语)实现外,其它类型的通过对象头的MarkWord实现。
三、Synchronized执行过程
-
检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁。
-
如果不是,则使用CAS将当前线程的ID替换Mark Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1。
-
如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
-
当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁。
-
如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
-
如果自旋成功则依然处于轻量级状态。
-
如果自旋失败,则升级为重量级锁。