Synchronized关键字
一、原理
1.1 对象头
- 对象:对象头、实例变量、填充数据
- 对象头结构(2个字,数组多出来的1个字记录的是数组长度)
| 虚拟机位数 | 对象头结构 | 说明 |
|---|---|---|
| 32/64 bit | Mark Word | 存放对象运行时数据:哈希码(hashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等 |
| 32/64 bit | Class Metadata Address | 类型指针指向对象的类元数据(instanceof)、JVM通过这个指针获取对象是那个类的实例 |
1.2. Mark Word 结构
- 32位正常
| 锁状态 | 25bit | 4bit | 1bit(是否是偏向锁) | 2bit(锁标志位) |
|---|---|---|---|---|
| 无锁状态 | 对象HashCode | 对象分代年龄 | 0 | 01 |
- 32位细分
![]()
二、锁队列
- C++的 ObjectMonitor
ObjectMonitor() {
_header = NULL;
_count = 0; //记录个数
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL; "当前线程指针"
_WaitSet = NULL; "处于wait状态的线程,会被加入到_WaitSet队列"
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; "处于等待锁block状态的线程,会被加入到该列表队列"
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}
- 示意图
- 先进入 _EntryList集合排队
- 然后获取锁,_Owner标记位当前线程。
- 当执行 wait() 方法,则进入 _WaitSet集合中,等待唤醒

三、各阶段锁
-
偏向锁(没有锁竞争)<JDK1.6>
- 经过研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。
- 偏向锁的核心思想是
- 如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构,
- 当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作,从而也就提供程序的性能。
- 对于没有锁竞争的场合,偏向锁有很好的优化效果,毕竟极有可能连续多次是同一个线程申请相同的锁。
- 但是对于锁竞争比较激烈的场合,偏向锁就失效了,因为这样场合极有可能每次申请锁的线程都是不相同的,因此这种场合下不应该使用偏向锁,否则会得不偿失,需要注意的是,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。
-
轻量级锁(同步周期内都不存在竞争:交替执行)<JDK1.6>
- 倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的),此时Mark Word 的结构也变为轻量级锁的结构。
- 轻量级锁能够提升程序性能的依据是对绝大部分的锁,在整个同步周期内都不存在竞争,注意这是经验数据。
- 轻量级锁所适应的场景是 线程交替执行同步块的场合,如果存在同一时间访问同一锁的场合,就会导致轻量级锁膨胀为重量级锁。
-
重量级锁(同一时间访问同一锁)
- 线程挂起
四、案例
- java 代码
package com.fxl.fight2.service.syn;
public class SyncObject {
public int i;
public void syncTask() {
// 同步代码库
synchronized (this) {
i++;
}
}
}
- javap 反解析
public class com.fxl.fight2.service.syn.SyncObject {
public int i;
public com.fxl.fight2.service.syn.SyncObject();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void syncTask();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter "加锁"
4: aload_0
5: dup
6: getfield #2 // Field i:I
9: iconst_1
10: iadd
11: putfield #2 // Field i:I
14: aload_1 "锁退出"
15: monitorexit
16: goto 24
19: astore_2
20: aload_1
21: monitorexit
22: aload_2
23: athrow
24: return
Exception table:
from to target type
4 16 19 any
19 22 19 any
}
- 结构
3: monitorenter "加锁"
....
15: monitorexit "锁退出"
16: goto 24
...
21: monitorexit

浙公网安备 33010602011771号