Java对象头Mark Word状态与锁膨胀过程剖析

作者:wuminyu日期:2026/8/6

Java对象头Mark Word状态与锁膨胀过程剖析

  • 前言
  • 对象头Mark Word状态与锁膨胀过程剖析
    • 1. 64位 HotSpot JVM 下 Mark Word 内存布局
      • 64位 JVM Mark Word 位结构图表
        • C++ 头文件位常量定义 (`markOop.hpp`)
    • 2. 状态机迁移全景与锁演进路线
    • 3. 偏向锁(Biased Locking)的加锁与撤销源码解析
      • 3.1 偏向锁的快速进入(Fast Path)
        • 3.2 偏向锁的撤销(Revocation)
    • 4. 轻量级锁(Lightweight Locking)的入锁与压栈源码解析
      • 4.1 BasicLock 结构
        • 4.2 轻量级锁的加锁流程(`ObjectSynchronizer::fast_enter`)
    • 5. 核心膨胀逻辑:`ObjectSynchronizer::inflate` 源码逐行精析
    • 6. 重量级锁(ObjectMonitor)的互斥与等待机制
      • 6.1 `ObjectMonitor` 核心字段布局
        • 6.2 竞争入口:`ObjectMonitor::enter`
        • 6.3 线程入队与操作系统级挂起:`ObjectMonitor::EnterI`
        • 6.4 释放锁与唤醒策略:`ObjectMonitor::exit`
    • 7. 总结:
      • 1、锁演进核心机制对比
        • 2、Mark Word锁膨胀全景状态转换图

前言

本文旨在记录近期研读Java源码的学习心得与疑难问题。由于个人理解水平有限,文中内容难免存在疏漏,恳请读者不吝指正。

对象头Mark Word状态与锁膨胀过程剖析

1. 64位 HotSpot JVM 下 Mark Word 内存布局

在 OpenJDK 8u 中,对象的内存布局分为对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对象头由 Mark Word(标记字)和 Klass Word(类型指针,可能被压缩为 32 位 narrowKlass)组成。

Mark Word 在 64 位 JVM (hotspot/src/share/vm/oops/markOop.hpp) 中占用 64 bits (8 Bytes)。JVM 巧用低位标志位(Tag bits)对不同锁状态下的内存结构进行复用,消除额外的内存开销。

64位 JVM Mark Word 位结构图表

锁状态 (Lock State)25 bits31 bits1 bit2 bits4 bits1 bit (biased_lock)2 bits (lock)说明
无锁 (Unlocked)未使用identity_hashcode未使用cms_epochage001普通未加锁状态
偏向锁 (Biased)__JavaThread (54bits)_*epoch (2bits)未使用cms_epochage101单线程独占持有
轻量级锁 (Lightweight)ptr_to_lock_record (指向栈帧中 BasicLock 的指针,62bits)00多线程无竞争 CAS 膨胀
重量级锁 (Heavyweight)ptr_to_heavyweight_monitor (指向 ObjectMonitor 的指针,62bits)10存在激烈锁竞争
GC 标记 (Marked for GC)ptr_to_forwardee (指向对象拷贝新地址,62bits)11GC 垃圾回收标记

C++ 头文件位常量定义 (markOop.hpp)

1// hotspot/src/share/vm/oops/markOop.hpp
2
3class markOopDesc: public ooDesc {
4  enum {
5    age_bits                 = 4,
6    lock_bits                = 2,
7    biased_lock_bits         = 1,
8    max_hash_bits            = 31,
9    hash_bits                = 31,
10    cms_bits                 = 1,
11    epoch_bits               = 2,
12
13    // 位移偏移量计算
14    lock_shift               = 0,
15    biased_lock_shift        = lock_bits,                           // 2
16    age_shift                = lock_bits + biased_lock_bits,        // 3
17    cms_shift                = age_shift + age_bits,                // 7
18    epoch_shift              = cms_shift + cms_bits,                // 8
19    hash_shift               = epoch_shift + epoch_bits,            // 10
20
21    // 位掩码 (Masks)
22    lock_mask                = right_n_bits(lock_bits),             // 0x03
23    lock_mask_in_place       = lock_mask << lock_shift,
24    biased_lock_mask         = right_n_bits(biased_lock_bits),      // 0x01
25    biased_lock_mask_in_place= biased_lock_mask << biased_lock_shift,// 0x04
26    biased_lock_bit_in_place = biased_lock_mask_in_place,
27    biased_lock_alignment    = 1 << (biased_lock_shift + biased_lock_bits),
28
29    // 锁标记常量 (Tag Values)
30    locked_value             = 0, // 00: 轻量级锁
31    unlocked_value           = 1, // 01: 无锁
32    monitor_value            = 2, // 10: 重量级锁 (ObjectMonitor)
33    marked_value             = 3, // 11: GC 标记
34    biased_lock_pattern      = 5  // 101: 偏向锁 (biased_lock:1, lock:01)
35  };
36};
37
38

2. 状态机迁移全景与锁演进路线

Java 对象在 HotSpot 中的锁生命周期是一个单向膨胀为主(偏向锁可被撤销为无锁或直接膨胀为轻量级锁)的状态机迁移过程:

1                    ┌─────────────────────────┐
2                          可偏向匿名对象       
3                     (Biased, ThreadID = 0)  
4                    └────────────┬────────────┘
5                                  首次加锁 (CAS 写入 ThreadID)
6                                 
7┌──────────────┐    撤销偏向     ┌─────────────────────────┐
8  无锁状态     ◄───────────────┤        偏向锁           
9 (Unlocked)                     (Biased, ThreadID != 0) 
10└──────┬───────┘                 └────────────┬────────────┘
11                                             
12        多线程交替执行                         存在竞争 (安全点触发撤销)
13                                             
14┌──────────────────────────────────────────────────────────┐
15                      轻量级锁                            
16  (Mark Word 指向当前线程栈帧中的 BasicLock / Lock Record)   
17└────────────────────────────┬─────────────────────────────┘
18                             
19                              存在激烈竞争 (CAS 自旋失败 / 膨胀函数被调用)
20                             
21┌──────────────────────────────────────────────────────────┐
22                      重量级锁                            
23    (Mark Word 指向 C++ 堆中分配的 ObjectMonitor 结构)    
24└──────────────────────────────────────────────────────────┘
25
26

3. 偏向锁(Biased Locking)的加锁与撤销源码解析

偏向锁用于消除无竞争环境下的同步开销。通过在 Mark Word 中记录当前持有锁的 Java 线程 ID (JavaThread*),后续该线程进入同步块时仅需比较 Thread ID,避免任何 CAS 原子指令。

3.1 偏向锁的快速进入(Fast Path)

当 JVM 启用偏向锁 (-XX:+UseBiasedLocking,JDK 8 中默认延迟 4 秒启动) 时,解释器在执行 monitorenter 字节码时通过汇编/C++ 解释器直接校验 Mark Word:

1// hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
2
3markOop mark = obj->mark();
4if (mark->has_bias_pattern()) { // 检查 low 3 bits 是否为 101
5  // 校验当前 Mark Word 中的 epoch 是否有效,且线程 ID 是否等于当前线程
6  address current = (address) THREAD;
7  uintptr_t bits = (uintptr_t) mark;
8  if ((bits & (biased_lock_mask_in_place | topic_mask)) == 
9      ((uintptr_t) current | prototype_header)) {
10    // 命中偏向锁,直接获得锁,无任何 CAS 开销
11    success = true;
12  } else if ((bits & biased_lock_mask_in_place) == 0) {
13    // epoch 过期,尝试重偏向 (Rebias)
14    // ...
15  } else {
16    // 偏向了其他线程,或者偏向锁未设置 Thread ID,使用 CAS 尝试偏向当前线程
17    markOop new_mark = (markOop) ((uintptr_t) mark | (uintptr_t) current);
18    if (Atomic::cmpxchg_ptr(new_mark, obj->mark_addr(), mark) == mark) {
19      success = true;
20    } else {
21      // CAS 失败,说明存在竞争,进入慢速路径 (Slow Path) 进行偏向锁撤销与锁膨胀
22      InterpreterRuntime::monitorenter(THREAD, elem);
23    }
24  }
25}
26
27

3.2 偏向锁的撤销(Revocation)

当另一个线程尝试获取已被偏向的对象锁时,偏向锁必须被撤销 (Revoke)。撤销过程必须等待全局安全点(Safepoint),以挂起偏向锁的持有者线程,检查其是否仍在同步块中。

核心实现源码位于 hotspot/src/share/vm/runtime/biasedLocking.cpp

1BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
2  assert(get_safepoint_safepoint_counter() > 0, "must be at safepoint");
3  
4  markOop mark = obj->mark();
5  if (!mark->has_bias_pattern()) {
6    return NOT_BIASED;
7  }
8
9  // 1. 获取偏向锁持有的 C++ 线程指针 JavaThread*
10  JavaThread* biased_thread = mark->biased_locker();
11  
12  // 2. 检查偏向线程是否存活
13  bool is_alive = false;
14  if (biased_thread != NULL) {
15    is_alive = Threads::is_supported_java_thread_obj(biased_thread->threadObj()) &&
16               !biased_thread->is_terminated();
17  }
18
19  // 3. 如果偏向线程已经终止,将对象重置为无锁状态或匿名偏向状态
20  if (!is_alive) {
21    if (attempt_rebias) {
22      obj->set_mark(markOopDesc::biased_locking_prototype());
23    } else {
24      obj->set_mark(markOopDesc::prototype()); // 恢复为 01 无锁状态
25    }
26    return BIAS_REVOKED;
27  }
28
29  // 4. 如果偏向线程仍存活,遍历其调用栈帧 (Stack Walk),检查该对象是否还在被该线程锁住
30  GrowableArray<MonitorInfo*>* cached_monitors = get_or_compute_monitors(biased_thread);
31  BasicObjectLock* highest_lock = NULL;
32  for (int i = 0; i < cached_monitors->length(); i++) {
33    MonitorInfo* mon_info = cached_monitors->at(i);
34    if (mon_info->owner() == obj()) {
35      highest_lock = mon_info->lock(); // 找到了对应的 BasicObjectLock 记录
36      break;
37    }
38  }
39
40  if (highest_lock != NULL) {
41    // 偏向线程仍处于同步块内部:将偏向锁直接升级为轻量级锁
42    // 修改栈帧中最高层 BasicLock  Displaced Mark Word 为无锁原型 (prototype)
43    highest_lock->set_displaced_header(markOopDesc::prototype());
44    
45    // 直接将对象的 Mark Word 指向该线程栈帧中的 BasicLock 指针
46    obj->release_set_mark(markOopDesc::encode(highest_lock));
47  } else {
48    // 偏向线程已不在同步块中:撤销偏向,恢复无锁状态
49    if (attempt_rebias) {
50      obj->set_mark(markOopDesc::biased_locking_prototype());
51    } else {
52      obj->set_mark(markOopDesc::prototype());
53    }
54  }
55
56  return BIAS_REVOKED;
57}
58
59

4. 轻量级锁(Lightweight Locking)的入锁与压栈源码解析

轻量级锁设计用于线程交替执行同步块(无激烈竞争)的场景。它的实现依赖于 Java 线程栈帧(Stack Frame)上的内存区域:BasicLock(锁记录 / Lock Record)。

4.1 BasicLock 结构

BasicLock 定义在 hotspot/src/share/vm/runtime/basicLock.hpp 中:

1class BasicLock VALUE_OBJ_CLASS_SPEC {
2 private:
3  volatile markOop _displaced_header; // 存储对象原有的 Mark Word 备份
4 public:
5  markOop displaced_header() const               { return _displaced_header; }
6  void set_displaced_header(markOop header)      { _displaced_header = header; }
7};
8
9class BasicObjectLock VALUE_OBJ_CLASS_SPEC {
10 private:
11  BasicLock _lock;                             // Lock Record 实体
12  oop       _obj;                              // 指向被加锁的 Java 对象
13};
14
15

4.2 轻量级锁的加锁流程(ObjectSynchronizer::fast_enter

核心代码位于 hotspot/src/share/vm/runtime/synchronizer.cpp

1void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
2 if (UseBiasedLocking) {
3    if (!SafepointSynchronize::is_at_safepoint()) {
4      // 偏向锁处理路径
5      BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
6      if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
7        return;
8      }
9    } else {
10      BiasedLocking::revoke_at_safepoint(obj);
11    }
12  }
13
14  // 慢速/轻量级锁进入路径
15  slow_enter(obj, lock, THREAD);
16}
17
18void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
19  markOop mark = obj->mark();
20
21  // 1. 如果当前对象处于无锁状态 (mark->is_unlocked() 返回 true,即 low 2bits == 01)
22  if (mark->is_unlocked()) {
23    // a. 将对象当前的 Mark Word 备份到当前线程栈帧的 BasicLock  _displaced_header 
24    lock->set_displaced_header(mark);
25
26    // b. 使用 CAS 尝试将对象的 Mark Word 修改为指向 BasicLock 的指针
27    // markOopDesc::encode(lock) 将指针转为 low 2bits == 00  markOop
28    if (Atomic::cmpxchg_ptr(markOopDesc::encode(lock), obj->mark_addr(), mark) == mark) {
29      TEVENT (slow_enter: fast stacklock);
30      return; // CAS 成功,轻量级锁获取成功
31    }
32    // CAS 失败,产生竞争,落入下面的锁膨胀逻辑
33  } 
34  // 2. 如果对象已经是轻量级锁,检查是否是重入锁 (Lock Reentry)
35  else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
36    // 当前线程是该锁的持有者(重入):将 BasicLock  _displaced_header 设置为 NULL 作为重入标记
37    lock->set_displaced_header(NULL);
38    return;
39  }
40
41  // 3. 产生多线程并发竞争,或者二次重入校验失败:触发锁膨胀 (Inflation) 升级为重量级锁
42  lock->set_displaced_header(markOopDesc::unused_mark());
43  ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
44}
45
46

5. 核心膨胀逻辑:ObjectSynchronizer::inflate 源码逐行精析

当轻量级锁 CAS 失败,或者调用了 Object.wait() / Object.hashCode() 方法(重写了 Mark Word 导致轻量级锁无处存放 HashCode)时,JVM 必须将锁膨胀 (Inflate) 为重量级锁 ObjectMonitor

ObjectSynchronizer::inflate() 是 OpenJDK 中最关键的锁转换状态机实现(采用自旋锁与 CAS 控制状态转移),定义在 hotspot/src/share/vm/runtime/synchronizer.cpp

1ObjectMonitor* ObjectSynchronizer::inflate (Thread * Self, oop object) {
2  // 避免自旋时的无谓计算
3  OrderAccess::fence();
4
5  for (;;) {
6    const markOop mark = object->mark();
7    assert (!mark->has_bias_pattern(), "invariant");
8
9    // ===================================================================
10    // 情况 1:锁已经是重量级锁 (Inflated),最简单直接的路径
11    // ===================================================================
12    if (mark->has_monitor()) {
13      ObjectMonitor * monitor = mark->monitor();
14      assert (monitor->object() == object, "invariant");
15      return monitor; // 直接返回已存在的 ObjectMonitor 指针
16    }
17
18    // ===================================================================
19    // 情况 2:膨胀中状态 (INFLATING),其他线程正在对此对象进行 inflate 操作
20    // ===================================================================
21    if (mark == markOopDesc::INFLATING()) {
22      // 遇到过渡态,通过 spin_yield 避让,等待其他线程完成膨胀
23      tevent(Inflate: Spin);
24      ReadStableMark(object); // 自旋等待 Mark Word 变为 stable
25      continue;
26    }
27
28    // ===================================================================
29    // 情况 3:当前为轻量级锁 (Lightweight Locked) 状态
30    // ===================================================================
31    if (mark->has_locker()) {
32      // 1. 从全局预分配池或线程私有块 (omInUseList) 中分配一个未使用的 ObjectMonitor
33      ObjectMonitor * m = omAlloc (Self);
34
35      m->Recycle();
36      m->_mark    = mark;
37
38      // 2.  Mark Word 设置为 INFLATING() (位标记为 00,但 displaced mark  NULL)
39      // 使用 CAS 尝试争夺膨胀控制权
40      markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
41      if (cmp != mark) {
42        // CAS 争夺失败,释放刚才分配的 monitor,重新自旋
43        omRelease(Self, m, true);
44        continue;
45      }
46
47      // 3. CAS 成功!当前线程独占膨胀控制权
48      // 提取轻量级锁在持锁线程栈帧上的 Displaced Mark Word
49      markOop dmw = mark->locker()->displaced_header();
50      assert (dmw != NULL, "invariant");
51
52      // 如果轻量级锁是重入状态 (dmw == NULL),需要向上遍历栈帧寻找最初的那个 非NULL Displaced Mark Word
53      if (dmw == NULL) {
54        // 逻辑简化:恢复对象原始的无锁原型
55        dmw = markOopDesc::prototype();
56      }
57
58      // 4. 初始化 ObjectMonitor 内部字段
59      m->set_header(dmw);                           // 转移保存原始的 Mark Word (包含 identity hash code 等)
60      m->set_owner(mark->locker());                // 暂时将 owner 设置为持有轻量级锁的 BasicLock 指针
61      m->set_object(object);
62
63      // 5. 关键原子的状态更新:发布重量级锁
64      // 将对象的 Mark Word 原子更新为指向 ObjectMonitor 实体,并附加 tag = 10 (monitor_value)
65      object->release_set_mark(markOopDesc::encode(m));
66
67      // 6. 返回创建成功的 ObjectMonitor
68      return m;
69    }
70
71    // ===================================================================
72    // 情况 4:当前处于无锁状态 (Unlocked, low 2bits == 01)
73    // ===================================================================
74    assert (mark->is_unlocked(), "invariant");
75    
76    // 1. 分配 ObjectMonitor 节点
77    ObjectMonitor * m = omAlloc (Self);
78
79    m->Recycle();
80    m->set_header(mark);                          // 直接保存当前无锁的 Mark Word
81    m->set_owner(NULL);                           // 暂无可竞争的 Owner
82    m->set_object(object);
83
84    // 2. CAS 将对象 Mark Word 直接指向 ObjectMonitor 指针 (tag 10)
85    if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) {
86      // CAS 失败,说明有其他线程竞争加锁或膨胀,释放 monitor 并重试
87      m->set_object(NULL);
88      omRelease(Self, m, true);
89      continue;
90    }
91
92    // 3. 膨胀成功,返回 ObjectMonitor
93    return m;
94  }
95}
96
97

6. 重量级锁(ObjectMonitor)的互斥与等待机制

一旦锁演变膨胀为重量级锁,后续所有的竞争与挂起逻辑由 C++ 实现的 ObjectMonitor 对象接管。

6.1 ObjectMonitor 核心字段布局

结构定义在 hotspot/src/share/vm/runtime/objectMonitor.hpp

1class ObjectMonitor {
2  markOop           _header;       // 存储原始的 Mark Word (包含 HashCode、age 等)
3  void*             _object;       // 指向该 Monitor 关联的 Java 对象引用
4  void*             _owner;        // 指向当前持有锁的线程 (JavaThread*)  BasicLock 指针
5  
6  intptr_t          _recursions;   // 锁重入次数 (0 表示无重入)
7  intptr_t          _count;        // 挂起等待锁的线程计数
8  
9  ObjectWaiter*     _cxq;          // 竞争队列 (ContentionQueue):Lock-free LIFO 栈,单向链表
10  ObjectWaiter*     _EntryList;    // 双向链表:准备获取锁的候选线程队列
11  ObjectWaiter*     _WaitSet;      // 双向链表:调用 Object.wait() 被挂起的线程队列
12  
13  Thread*           _QueueWaiter;  // 队列保护锁标识
14  int               _WaitSetLock;  // 保护 WaitSet 的互斥信号量
15};
16
17

6.2 竞争入口:ObjectMonitor::enter

当线程试图获取重量级锁时,调用 ObjectMonitor::enter (hotspot/src/share/vm/runtime/objectMonitor.cpp):

1void ATTR ObjectMonitor::enter(TRAPS) {
2  Thread * const Self = THREAD;
3  void * cur;
4
5  // 1. 快速 CAS 尝试获取锁:将 _owner  NULL 修改为当前线程
6  cur = Atomic::cmpxchg_ptr(Self, &_owner, NULL);
7  if (cur == NULL) {
8    return; // 抢锁成功,直接返回
9  }
10
11  // 2. 检查是否重入 (Self 即为当前持有锁的线程)
12  if (cur == Self) {
13    _recursions++;
14    return;
15  }
16
17  // 3. 检查当前 owner 是否为轻量级锁指针 (如果刚才由轻量级锁膨胀而来,owner 暂存为 BasicLock*)
18  if (Self->is_lock_owned((address)cur)) {
19    assert(_recursions == 0, "internal error");
20    _recursions = 1;
21    _owner = Self; // 修正 owner 为当前 C++ JavaThread* 指针
22    return;
23  }
24
25  // 4. 竞争失败,准备进入阻塞队列 (Slow Path)
26  Self->_ParkEvent->Reset();
27  
28  // 5. 自旋优化尝试 (Adaptive Spinning)
29  if (Knob_SpinLimit > 0) {
30    if (TrySpin(Self) > 0) {
31      return; // 自旋成功获取到了锁
32    }
33  }
34
35  // 6. 自旋失败,加入 cxq / EntryList 并挂起线程
36  EnterI (THREAD);
37}
38
39

6.3 线程入队与操作系统级挂起:ObjectMonitor::EnterI

1void ATTR ObjectMonitor::EnterI (TRAPS) {
2    Thread * Self = THREAD;
3
4    // 1. 创建 ObjectWaiter 包装节点
5    ObjectWaiter node(Self);
6    Self->_ParkEvent->Reset();
7
8    // 2. 利用 CAS 将当前节点压入 _cxq 栈顶 (无锁 LIFO 链表)
9    ObjectWaiter * nxt;
10    for (;;) {
11        node._next = nxt = _cxq;
12        if (Atomic::cmpxchg_ptr(&node, &_cxq, nxt) == nxt) break;
13        
14        // 再次尝试抢锁
15        if (TryLock (Self) > 0) return;
16    }
17
18    // 3. 阻塞循环:调用 OS 底层 API 挂起当前线程
19    for (;;) {
20        if (TryLock (Self) > 0) break; // 再次尝试获取锁
21
22        // 基于 OS 的底层的 park 机制 (Linux 下为 futex / pthread_cond_wait)
23        Self->_ParkEvent->park(); // 线程在此处被挂起 (Suspend)
24
25        // 线程被 unpark 唤醒后继续循环抢锁
26    }
27
28    // 4. 抢锁成功,从队列中移除自身节点
29    UnlinkAfterAcquire(Self, &node);
30}
31
32

6.4 释放锁与唤醒策略:ObjectMonitor::exit

当重量级锁持有者退出的时,调用 ObjectMonitor::exit

1void ATTR ObjectMonitor::exit(bool markObjectIsLocked, TRAPS) {
2   Thread * Self = THREAD;
3
4   // 1. 重入计数递减
5   if (_recursions > 0) {
6     _recursions--;
7     return;
8   }
9
10   // 2. 释放 Owner 控制权
11   OrderAccess::release_store_ptr(&_owner, NULL); // 写屏障清空 _owner
12   OrderAccess::fence();                          // 内存屏障保证可见性
13
14   // 3. 检查是否有等待被唤醒的线程 (_cxq  _EntryList 不为空)
15   if (_EntryList == NULL && _cxq == NULL) {
16      return; // 无竞争者,直接离开
17   }
18
19   // 4. 挑选唤醒节点 (Successor Selection)
20   ObjectWaiter * w = NULL;
21   
22   // 根据 QMode 策略,决定是将 _cxq 转移到 _EntryList,还是直接唤醒 _cxq 栈顶
23   if (_EntryList == NULL) {
24      //  _cxq 整体移动到 _EntryList 变为 FIFO 顺序
25      _EntryList = _cxq;
26      _cxq = NULL;
27   }
28
29   w = _EntryList;
30   if (w != NULL) {
31      // 5. 唤醒被阻塞的继承者线程
32      Thread::SpinAcquire(&_QueueWaiter, "Monitor Exit");
33      
34      // 调用 OS 级别的 unpark 唤醒 C++ 线程
35      w->_thread->_ParkEvent->unpark();
36      
37      Thread::SpinRelease(&_QueueWaiter);
38   }
39}
40
41

7. 总结:

1、锁演进核心机制对比

锁类型核心标志 (Mark Word)触发条件加锁开销适用场景关键 HotSpot 结构
偏向锁`ThreadID101`单线程访问无 CAS(仅比对 Thread ID)只有一个线程反复进入同步块
轻量级锁`BasicLock*00`多线程交替执行(无竞争)1 次 CAS(修改 Mark Word 指向栈帧)任务执行极快,交替抢锁
重量级锁`ObjectMonitor*10`存在激烈的多线程并发竞争频繁 CAS + OS 线程上下文切换 (park/unpark)高并发长时临界区操作

2、Mark Word锁膨胀全景状态转换图

结合 OpenJDK 8源码实现,锁状态的完整转变轨迹如下:

1+---------------------------------------------------------------------------------------------------------+
2|                                           [新创建对象]                                                  |
3|                                                |                                                        |
4|                            开启偏向锁 (101)    |    禁用偏向锁 (001)                                    |
5|                                                v                                                        |
6|                                       +------------------+                                              |
7|                                       |   匿名偏向 (101)  |                                              |
8|                                       +------------------+                                              |
9|                                                |                                                        |
10|                                       首次 CAS 获得偏向锁                                               |
11|                                                v                                                        |
12|                                       +------------------+                                              |
13|                                       |   偏向锁状态(101)|                                              |
14|                                       +------------------+                                              |
15|                                                |                                                        |
16|                                       竞争 / 调用 hashCode()                                            |
17|                                                v                                                        |
18|   +-------------------+               偏向锁撤销(Safepoint)              +--------------------------+  |
19|   |   无锁状态 (001)  |<------------------------------------------------>|  轻量级锁 (00)           |  |
20|   +-------------------+                                                  +--------------------------+  |
21|             |                                                                         |                 |
22|      调用 wait() / hashCode()                                              CAS 失败 / 存在锁竞争        |
23|             |                                                                         |                 |
24|             +----------------------------> [锁膨胀过程] <-----------------------------+                 |
25|                                                 |                                                       |
26|                                  1. omAlloc 分配 ObjectMonitor                                           |
27|                                  2. CAS 将对象头 Mark Word 置为 INFLATING (0)                            |
28|                                  3. 填充 ObjectMonitor 属性 (header, owner, object)                     |
29|                                  4. CAS  Mark Word 设置为 ObjectMonitor* (10)                        |
30|                                                 v                                                       |
31|                                       +------------------+                                              |
32|                                       |   重量级锁 (10)  |                                              |
33|                                       +------------------+                                              |
34+---------------------------------------------------------------------------------------------------------+
35
36

Java对象头Mark Word状态与锁膨胀过程剖析》 是转载文章,点击查看原文


相关推荐


2026 哪个远程控制软件好用?国内海外 6 款主流远程软件深度测评(附评分表与选型建议)
禁止默2026/7/28

2026 年了,远程控制软件早就不是"偶尔帮老妈修电脑"的低频工具了——居家连公司工位改方案、出差路上用平板回邮件、周末秒回 OA、被控端跑训练任务、远程串流玩 3A,这些场景已经把远程软件变成了天天开的生产力底座。 但"哪个好用"这个问题在 2026 年变得更难回答了,原因是市场出现了三条暗线: 国内三巨头分层明显:UU 远程靠网易的网络底子杀进来,把 4K/144fps、端口映射、远程终端全做成了免费;ToDesk 免费版开始卡时长;向日葵免费版广告越塞越多,并且开始排队收费。


让家里网速有据可查:用MySpeed做一个24小时测速看板
是店小二呀2026/7/20

前言 很多人办理宽带时看到的是500M、1000M,可真正用起来却不是那么回事。晚上看视频卡顿,家里多人同时上网就变慢,联系运营商时,对方一句“后台检测正常”,问题往往就很难继续推进。 问题不一定出在你不会测速,而是普通测速方式很难留下连续证据。偶尔打开第三方测速网站测一次,只能说明当时那一刻的结果,不能反映一天内不同时段的波动,也很难判断是不是晚高峰、Wi-Fi环境或线路质量造成的影响。 如果家里本来就有群晖NAS,可以把它变成一台长期在线的测速服务器。MySpeed就是适合这种场景的轻


PDF解析实现
马里马里奥-2026/7/12

1. 项目背景与需求分析 在现代Web应用中,PDF 文档处理是一个常见但复杂的需求。无论是企业 OA 系统、在线教育平台还是知识管理工具,都需要能够高效解析 PDF 内容。本次作业要求实现一个中间件,专门处理前端上传的PDF文件,具体要求如下: 输入格式:接收 Base64 编码的 PDF 数据核心功能:将 Base64 转换为正常 PDF 文件并提取文本内容输出要求:将提取的文本内容完整放入 system_message 中,作为后续对话的上下文扩展目标:最终版本应支持上传或发送包含完整


【Agent 学习日记】从问题到答案:RAG系统完整处理流程与核心机制深度拆解
小假是真的2026/7/4

目录 🍬前言 🍬一、 RAG 系统全流程总览(宏观视角) 🍬二、 离线预处理:决定 RAG 效果的上限 🍬三、 在线推理第一步:问题是如何被“拆解”的?(Query 拆解) 🍬四、 向量检索与重排序:从“大海捞针”到“精准定位” 🍬五、 大模型(LLM)在 RAG 中到底负责什么? 🍬六、 最终输出:不仅是“答案” 🍬七、 关键痛点与优化方向(总结展望) 🍬八、面试回答 🍡RAG完整处理流程 🍡问题如何拆解? 🍡大模型负责什么? 🍡最终输出什么


GitHub 热榜项目 - 周榜(2026-06-21)
CoderJia_2026/6/26

GitHub 热榜项目 - 周榜(2026-06-21) 生成于:2026-06-21 统计摘要 共发现热门项目: 21 个 Token赞助:siliconflow 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 本期热点趋势总结 本期 GitHub 热榜呈现出明显的 AI 工程化 与基础设施化 趋势:MCP 服务、Agent 技能、提示词安全扫描、RAG 压缩、代码知识图谱等项目集中爆发,说明开发重点已


《PyTorch 深度修炼》Dataset 和 DataLoader:数据如何喂给模型
闵孚龙2026/6/17

一、模型吃的不是文件,是 Batch Tensor 很多人刚学 PyTorch,会把数据加载理解成“读文件”。这个理解太浅。 训练模型时,真正进入模型的不是图片路径,不是 JSON,不是数据库记录,而是整理好的 Batch Tensor。 Dataset 负责回答一个问题:一个样本怎么取。DataLoader 负责回答另一个问题:怎样高效、稳定、成批地把样本送到训练循环。 所以 DataLoader 不是一个普通 for 循环。它是一条数据流水线。它管顺序、管批次、管拼接、管多进程、管预


Java Spring Data JPA 实战指南:Repository 查询、分页与实体映射
唐青枫2026/6/10

简介 Spring Data JPA 是 Spring Data 家族里专门用来简化 JPA 开发的模块。 它不是一个新的 ORM 规范。 更准确地说: JPA 是规范 Hibernate 是常见实现 Spring Data JPA 是 Spring 对 JPA Repository 的封装 在 Spring Boot 项目里,常见调用链大致是: Controller | v Service | v Repository | v Spring Data JPA |


阿里云ECS部署YOLO教程
MR_Colorful2026/6/2

1、阿里云注册 在官网注册账号:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台 2、ECS配置选择 3、在阿里云 Workbench里为Ubuntu 18/20/22/24安装XFCE桌面(不推荐在这个里面使用,不好用!) stesteps1、通过VNC连接实例 step2、更新软件包列表和已安装的包 sudo apt update && sudo apt upgrade -y step3、安装XFCE桌面环境 sudo apt install -y xfce4 xfc


HarmonyOS 鸿蒙PC平台三方库移植:使用 vcpkg 移植 libzen(ZenLib)
展菲2026/5/25

网罗开发 (小红书、快手、视频号同名)   大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。 图书作者:《ESP32-C3 物联网工程开发实战》 图书作者:《SwiftUI 入门,进阶与实战》 超级个体:COC上海社区主理人 特约讲师:大学讲师,谷歌亚马逊分享嘉宾 科技


决定命运的,从来不是市场,而是你看待市场的方式
怕浪猫2026/5/4

真正拉开差距的,从来不是信息,而是认知。 在金融市场中,绝大多数人输掉的,不是技术,而是思维方式。 真正站在顶层的投资者,往往遵循一些看似简单、却极难长期执行的原则。这些原则,构成了投资世界的底层逻辑。 以下 9 种投资思维,不仅被反复验证,更塑造了历史上最成功的一批投资者。 一、长期主义:真正的财富,是"熬"出来的 "如果你不打算持有一只股票10年,那就不要持有10分钟。" —— Warren Buffett 真实故事:可口可乐的"慢性暴利" 1988年,巴菲特开始大量买入 Coca-

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读