在 Java 中,synchronized 关键字是实现线程同步的基础工具,用于确保多个线程在访问共享资源时能够按照预期的顺序执行,避免数据不一致的问题。synchronized 可以作用于方法或代码块,实现锁的机制,保证在同一时刻只有一个线程能进入同步区域。它在并发编程中尤为重要,因为通过锁的获取与释放来控制代码执行的互斥性,有助于保证多线程程序的安全性和正确性。本文将深入解析 Java synchronized 关键字的实现细节,通过源码揭示 JVM 内部如何管理和优化同步操作的机制。

synchronized

在 JVM 中,synchronized 的底层实现涉及锁的多个状态转换,包括偏向锁、轻量级锁和重量级锁,以优化不同并发场景下的性能。这些锁的状态转换由 JVM 自动管理,根据线程竞争的激烈程度动态调整。

下面的图来自 《深入理解Java虚拟机》。

JEP 374: Deprecate and Disable Biased Locking 已经对偏向锁进行废弃,不在本文讨论的范围内。

废弃原因是偏向锁由于维护成本巨大,而目前从中获取的性能提升有限。

Biased locking introduced a lot of complex code into the synchronization subsystem and is invasive to other HotSpot components as well. This complexity is a barrier to understanding various parts of the code and an impediment to making significant design changes within the synchronization subsystem. To that end we would like to disable, deprecate, and eventually remove support for biased locking.

jol 是一款观察对象内存布局的工具,使用 jol 可以看到对象的 markword 。

markword

笔者电脑是 64 位的,下面是 markword 在 64 位机器上的布局,与 32 位区别不大。

Mark Word (normal):
 64                     39                              8    3  0
  [.......................HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH.AAAA.TT]
         (Unused)                      (Hash Code)     (GC Age)(Tag)

markword 在 JVM 中主要有三个作用:

  1. 垃圾回收 —— 存储转发指针并跟踪对象的年龄
  2. 锁 —— 存储与轻量级和重量级锁相关的信息
  3. 哈希码 —— 存储对象一旦计算出的稳定标识哈希码

对象创建后获取 markword 的值,见源码

public class JOLSample_01_Basic {

    public static void main(String[] args) {
        A a = new A();
        out.println(ClassLayout.parseInstance(a).toPrintable());

        long markword = VM.current().getLong(a,0);
        printMarkWordBin(markword);
        printMarkBit(markword);
        printbiasBit(markword);
        printAgeBit(markword);
    }
    public static class A {
       boolean f;
    }
}

结果如下:

  1. markword bit 为 0b00000101
  2. mark bit 为 0b01 表示未锁定
  3. bias bit 为 0b1 表示可偏向
  4. age bit 为 0b0000 表示 GC 年龄为 0
jol.JOLSample_01_Basic$A object internals:
OFF  SZ      TYPE DESCRIPTION               VALUE
  0   8           (object header: mark)     0x0000000000000005 (biasable; age: 0)
  8   4           (object header: class)    0x00066a50
 12   1   boolean A.f                       false
 13   3           (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

markword bit: 00000101 
mark bit: 00000001 
bias bit: 00000001 
age bit: 00000000 

上面的代码是使用的是 OpenJDK 11 运行的,可以看到偏向的标志位与前文图中不符合。其原因在于 JDK 版本,下面是 OpenJDK 8 运行的结果,可以看到 bias bit 位 0x0

com.example.demo.JOLSample_01_Basic$A object internals:
OFF  SZ      TYPE DESCRIPTION               VALUE
  0   8           (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4           (object header: class)    0x00060a20
 12   1   boolean A.f                       false
 13   3           (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

markword bit: 00000001 
mark bit: 00000001 
bias bit: 00000000 
age bit: 00000000 

hashcode

当对象的 hashcode 方法被调用时,hash 值会被存入 markword 中,见源码

public static void main(String[] args) {
    A a = new A();

    int hashcode = a.hashCode();
    out.println(ClassLayout.parseInstance(a).toPrintable());
    out.println("a.hashCode() : " + toBinaryWithSpaces(hashcode));
    long markword = VM.current().getLong(a,0);
    printHashcodeBit(markword);//(markword >>> 8)
    printMarkWordBin(markword); 
}

下面使用 hashCode 方法获取的 hash 值与程序从 markword 中获取的一致。

jol.JOLSample_01_Hashcode$A object internals:
OFF  SZ      TYPE DESCRIPTION               VALUE
  0   8           (object header: mark)     0x0000005594a1b501 (hash: 0x5594a1b5; age: 0)
  8   4           (object header: class)    0x00066a50
 12   1   boolean A.f                       false
 13   3           (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

a.hashCode() : 01010101 10010100 10100001 10110101 
hash code bit: 01010101 10010100 10100001 10110101 
markword bit: 01010101 10010100 10100001 10110101 00000001 

源码

下面试 hashCode 源码,ObjectSynchronizer::FastHashCode 负责实际获取 hashCode,方法逻辑很多这里不赘述。

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  // as implemented in the classic virtual machine; return 0 if object is null
  return handle == nullptr ? 0 :
         checked_cast<jint>(ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)));
JVM_EN

// Register native methods of Object
void java_lang_Object::register_natives(TRAPS) {
  InstanceKlass* obj = vmClasses::Object_klass();
  Method::register_native(obj, vmSymbols::hashCode_name(), vmSymbols::void_int_signature(), 
  (address) &JVM_IHashCode, CHECK);
}

intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
    //omit
    hash = mark.hash();
      if (hash != 0) return hash; // if it has a hash, just return it
    hash = get_next_hash(current, obj);  // get a new hash
    temp = mark.copy_set_hash(hash);     // merge the hash into header
                                           // try to install the hash
    test = obj->cas_set_mark(temp, mark);
    if (test == mark) return hash; // if the hash was installed, return it
}

对象年龄

同样从 markwor 中可以获取对象年龄,源码

public static void main(String[] args) {
    A a = new A();
    for (int i = 0; i < 500; i++) {
        var bytes = new byte[1024 * 1024];
    }
    out.println(ClassLayout.parseInstance(a).toPrintable());
    long markword = VM.current().getLong(a, 0);
    printAgeBit(markword);
}
jol.JOLSample_01_Hashcode$A object internals:
OFF  SZ      TYPE DESCRIPTION               VALUE
  0   8           (object header: mark)     0x000000000000001d (biasable; age: 3)
  8   4           (object header: class)    0x00066a50
 12   1   boolean A.f                       false
 13   3           (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

age bit: 00000011 

当垃圾回收时,对象被复制,年龄就会增加。

if (dest_attr.is_young()) {
    if (age < markWord::max_age) {
        obj->incr_age();
    }
}

void oopDesc::incr_age() {
  markWord m = mark();
  if (m.has_displaced_mark_helper()) { //与 synchronized 有关
    m.set_displaced_mark_helper(m.displaced_mark_helper().incr_age());
  } else {
    set_mark(m.incr_age());
  }
}

Compact Object Headers

JEP 450: Compact Object Headers (Experimental) 对 Java 对象头进行优化,并且将在 OpenJDK 24 发布试验版本。

JEP 450 旨在将 64 位平台下对象 16 字节或者 12 字节(开启指针压缩)的对象头缩减为 8 字节。在 Java 中,大多数都是小对象,缩减对象头能降低 Java 程序占用内存近 20%。

//Compact object headers
Header (compact):
64                    42                             11   7   3  0
 [CCCCCCCCCCCCCCCCCCCCCCHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHVVVVAAAASTT]
 (Compressed Class Pointer)       (Hash Code)         /(GC Age)^(Tag)
                              (Valhalla-reserved bits) (Self Forwarded Tag)

上面是 JEP 450 实现的对象头结构,将 markword 和 class pointer 合并成 8 字节,因此不支持 synchronized 传统的基于 markword 的轻量级锁(也叫栈锁)和重量级锁。

This is problematic for compact object headers because it overwrites the object header and thus loses crucial type information. Therefore, compact object headers are not compatible with legacy locking. If the JVM is configured to run with both legacy locking and compact object headers then compact object headers are disabled.

新的 synchronized 锁可以参考:

  1. 轻量级锁- 8291555: Replace stack-locking with fast-locking
  2. 轻量级锁可重入- Recursive lightweight locking
  3. 重量级锁- 8315884: New Object to ObjectMonitor mapping

栈帧

看过一些资料的读者应该都知道 synchronized 轻量级锁需要借助于 Java 栈来实现。首先是将锁对象的 markword 拷贝到栈中,称之为 Lock Record 的区域,Lock Record 也会有指向对象,然后利用 CAS 操作将对象的 markword 指向 Lock Record。

下面的图来自 《深入理解Java虚拟机》。

在 JVM 线程的栈帧中,有一个叫做 monitors 的区域,这个区域存储的就是 Lock Record。monitors 是一个数组,大小根据运行时方法的情况进行分配。

//src/hotspot/cpu/aarch64/frame_aarch64.hpp

// Layout of asm interpreter frame:
//    [expression stack      ] * <- sp
//    [monitors[0]           ]   \
//     ...                        | monitor block size = k
//    [monitors[k-1]         ]   /
//    [frame initial esp     ] ( == &monitors[0], initially here)       initial_sp_offset
//    [byte code index/pointr]                   = bcx()                bcx_offset
//    [pointer to locals     ]                   = locals()             locals_offset
//    [constant pool cache   ]                   = cache()              cache_offset
//    [klass of method       ]                   = mirror()             mirror_offset
//    [extended SP           ]                                          extended_sp offset
//    [methodData            ]                   = mdp()                mdx_offset
//    [Method                ]                   = method()             method_offset
//    [last esp              ]                   = last_sp()            last_sp_offset
//    [sender's SP           ]                     (sender_sp)          sender_sp_offset
//    [old frame pointer     ]   <- fp           = link()
//    [return pc             ]
//    [last sp               ]
//    [oop temp              ]                     (only for native calls)
//    [padding               ]                     (to preserve machine SP alignment)
//    [locals and parameters ]
//                               <- sender sp
// ------------------------------ Asm interpreter ----------------------------------------

Lock Record 在 JVM 中使用 BasicObjectLock 表示,_lock 存储对象 markword,_obj 指向锁对象。

class BasicObjectLock {
  BasicLock _lock;// the lock, must be double word aligned
  oop       _obj; // object holds the lock;
}

再谈 GC

当 Java 进行 GC 的时候,会从 GC root 开始扫描存活的对象,其中一项内容就是就是扫描线程的栈帧。BasicObjectLock 既然会指向对象,那也必然会被扫描。

void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache) const {
  for (
    BasicObjectLock* current = interpreter_frame_monitor_end();
    current < interpreter_frame_monitor_begin();
    current = next_monitor_in_interpreter_frame(current)
  ) {
    current->oops_do(f);
  }
}

class BasicObjectLock {
   // GC support
  void oops_do(OopClosure* f) { f->do_oop(&_obj); }
}

BasicObjectLock 在栈帧中数目与 synchronized 一定具有某种联系。下面修改 JVM 源码打印日志来确定。

实验

首先修改 JVM 中 oops_interpreted_do 的代码,增加 count 计数器和日志输出,仅仅输出我们关心的方法 testCountMonitorInMethod

void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache) const {
  Thread *thread = Thread::current();
  methodHandle m (thread, interpreter_frame_method());
  int count = 0;
  for (
    BasicObjectLock* current = interpreter_frame_monitor_end();
    current < interpreter_frame_monitor_begin();
    current = next_monitor_in_interpreter_frame(current)
  ) {
     count++;
    current->oops_do(f);
  }
  const char* method_name = m()->name()->as_C_string();
  if (strcmp(method_name, "testCountMonitorInMethod") == 0) {
    tty->print_cr("Current method name: %s, basicObjectLock: %d", method_name, count);
  }
}

下面是 Java 代码,见源码

public class SyncTest {
    private Object lock = new Object();
    private Object lock1 = new Object();

    public static void main(String[] args) {
        new Thread(()->{ new SyncTest().testCountMonitorInMethod();}).start();
        smallObj();
    }

    public void testCountMonitorInMethod() {
       synchronized (lock) {
           synchronized (lock1) {
             sleep();
           }
       }
    }
}

首先确认 Java 版本是我们自己编译的版本,JDK 如何编译

下面是运行结果,结果显示栈帧中 BasicObjectLock 的数目位 2。

反复试验,结果如下表所示。

注意,这里的数目是指在 GC 过程中,正在使用的 BasicObjectLock 数目,并不是栈帧初始化时分配的 BasicObjectLock 数目。

可以看到实际使用的 BasicObjectLock 数目和当前持有锁对象的数目一致。

至于 BasicObjectLock 在栈帧中的容量,笔者猜测,与方法运行时持有的锁对象最多情况下一致,也就是最多时有多少 synchronized 代码块嵌套。

解释器

在 HotSpot 中,有两种解释器,模板解释器和 C++ 解释器,关于解释的讨论见 Interpreter模块。 HotSpot 默认使用的是模板解释器是汇编代码写的,较为晦涩,阅读难度较大。

Interpreter模块 文中说可以使用通过配置使用 C++ 解释器,笔者没有找到相关的配置,网上相关说法在最新 OpenJDK 中都无法生效。

后文笔者以 C++ 解释器,即 bytecodeInterpreter 介绍 synchronized 实现。

轻量级锁

C++ 解释器 解析器的入口在 BytecodeInterpreter::run,synchronized 关键字最终会生成 monitorentermonitorexit 字节码指令。

CASE(_monitorenter):monitorenter 指令进行解释执行。

void BytecodeInterpreter::run(interpreterState istate) {
  //omit
        CASE(_monitorenter): {
        oop lockee = STACK_OBJECT(-1);
        BasicObjectLock* limit = istate->monitor_base();
        BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
        BasicObjectLock* entry = nullptr;
        while (most_recent != limit ) {
          if (most_recent->obj() == nullptr) entry = most_recent;
          else if (most_recent->obj() == lockee) break;
          most_recent++;
        }
        //omit
    }
    //omit
}

对 monitors 进行遍历,找到符合条件或者的 BasicObjectLock,遍历从低地址一直到高地址。

intptr_t*             _stack_base;    // base of expression stack
// Layout of asm interpreter frame:
//    [expression stack      ] * <- sp
//    [monitors[0]           ]   \
//     ...                        | monitor block size = k
//    [monitors[k-1]         ]   /
//    [frame initial esp     ] ( == &monitors[0], initially here)       initial_sp_offset

后文将传统的轻量级栈锁称之为 LM_LEGACY, 新的轻量级锁称之为 LM_LIGHTWEIGHT,前者通过线程栈实现,后者通过数据结构的栈来实现。

LM_LEGACY

LM_LEGACY 是通常在网上看到的,基于 Java 栈实现的轻量级锁。它的实现有三个步骤:

  1. 保存锁对象到 BasicObjectLock 类型的 entry 中。
  2. 保存锁对象的 markword 到 entry 中。
  3. 使用 CAS 覆盖锁对象的 markword 为 entry 的地址。
entry->set_obj(lockee);
if (LockingMode == LM_LEGACY) {
      // Traditional fast locking.
      markWord displaced = lockee->mark().set_unlocked();
      entry->lock()->set_displaced_header(displaced);
      success = true;
      if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) {
        // Is it simple recursive case?
        if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) {
          entry->lock()->set_displaced_header(markWord::from_pointer(nullptr));
        } else {
          success = false;
        }
      }
      if (success) {
        THREAD->inc_held_monitor_count();
      }
}

这里要注意,由于字节对齐的限制存在,比如 BasicObjectLock 在 monitors 数组中的位置都是 8 字节对齐的,那么它们地址的最低三位都是 0,也就是说最后两位的标志位也都是 0,正好满足标识为 00 时表示轻量级锁。

// A BasicObjectLock associates a specific Java object with a BasicLock.
// It is currently embedded in an interpreter frame.

// Because some machines have alignment restrictions on the control stack,
// the actual space allocated by the interpreter may include padding words
// after the end of the BasicObjectLock.  Also, in order to guarantee
// alignment of the embedded BasicLock objects on such machines, we
// put the embedded BasicLock at the beginning of the struct.
class BasicObjectLock

LM_LIGHTWEIGHT

[REDO] Change LockingMode default from LM_LEGACY to LM_LIGHTWEIGHT 已经将 LockingMode 默认值改成 LM_LIGHTWEIGHT,并且后面将移除对 LM_LEGACY 的支持。

In the next release, we plan to change the default of the LockingMode flag from LM_LEGACY to LM_LIGHTWEIGHT. Project Lilliput needs the LockingMode flag to be LM_LIGHTWEIGHT. In a release sometime after the next release, we place to remove support for LM_LEGACY.

product(int, LockingMode, LM_LIGHTWEIGHT,                                 \
        "(Deprecated) Select locking mode: "                              \
        "0: (Deprecated) monitors only (LM_MONITOR), "                    \
        "1: (Deprecated) monitors & legacy stack-locking (LM_LEGACY), "   \
        "2: monitors & new lightweight locking (LM_LIGHTWEIGHT, default)") \
        range(0, 2)                                                       \

LightweightSynchronizer::enter 方法是 LM_LIGHTWEIGHT 的实现,也包含了新版基于 hash table 实现的重量级锁,将在 JDK 24 中发布。

//->InterpreterRuntime::monitorenter
inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
  if (LockingMode == LM_LIGHTWEIGHT) {
    LightweightSynchronizer::enter(obj, lock, current);
  } else {
    enter_legacy(obj, lock, current);
  }
}

下图是新版 synchronized 获取锁的逻辑。

Value-Based Classes

@jdk.internal.ValueBased 注解修饰的类称为 Value-Based Classes,详见 JEP 390: Warnings for Value-Based Classes 。通常包括下面的类:

  • The primitive wrapper classes in java.lang;

  • The class java.lang.Runtime.Version;

  • The “optional” classes in java.util: Optional, OptionalInt, OptionalLong, and OptionalDouble;

  • Many classes in the java.time API: Instant, LocalDate, LocalTime, LocalDateTime, ZonedDateTime, ZoneId, OffsetTime, OffsetDateTime, ZoneOffset, Duration, Period, Year, YearMonth, and MonthDay, and, in java.time.chrono: MinguoDate, HijrahDate, JapaneseDate, and ThaiBuddhistDate;

  • The interface java.lang.ProcessHandle and its implementation classes;

  • The implementation classes of the collection factories in java.util: List.of, List.copyOf, Set.of, Set.copyOf, Map.of, Map.copyOf, Map.ofEntries, and Map.entry.

由于后续对需要对 Valhalla 项目的支持,如果这些类用于对象锁,根据 JVM 的配置会有对应的错误和警告。

  public static void main(String[] args) {
      Integer i = Integer.valueOf(1);
      synchronized (i) {
          System.out.println("sync use value based class");
      }
  }
-XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1

# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (synchronizer.cpp:485), pid=42306, tid=8707
#  fatal error: Synchronizing on object 0x00000007ffe5f3b8 of klass java.lang.Integer at review.Main.main(Main.java:7)
-XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2

[0.068s][info][valuebasedclasses] Synchronizing on object 0x00000007ffe5f3b8 of klass java.lang.Integer
[0.068s][info][valuebasedclasses] 	at review.Main.main(Main.java:7)
[0.068s][info][valuebasedclasses] 	- locked <0x00000007ffe5f3b8> (a java.lang.Integer)

方法 ObjectSynchronizer::handle_sync_on_value_based_class 负责处理 Value-Based Classes

轻量级锁实现

LM_LIGHTWEIGHT 是基于栈实现的,底层是一个数组。

class JavaThread: public Thread {
  LockStack _lock_stack;
}
class LockStack {
  static const int CAPACITY = 8;
  uint32_t _top;
  const uintptr_t _bad_oop_sentinel = badOopVal;
  oop _base[CAPACITY]
}

如果对象锁的状态是未锁定,则使用 CAS 获取锁。

inline bool LightweightSynchronizer::fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current) {
  markWord mark = obj->mark();
  while (mark.is_unlocked()) {
    ensure_lock_stack_space(current);
    // Try to swing into 'fast-locked' state.
    markWord locked_mark = mark.set_fast_locked();
    markWord old_mark = mark;
    mark = obj->cas_set_mark(locked_mark, old_mark);
    if (old_mark == mark) {
      lock_stack.push(obj);
      return true;
    } }
  return false;
}

获取轻量级锁的时候需要确保 lock_stack 还有容量,有两种措施:

  1. lock_stack 中已经被升级为重量级锁的对象移除。假如线程 A 持有锁对象的轻量级锁,如果此时线程 B 获取对象锁时,对象锁就会升级为重量级锁。

  2. lock_stack 中最早的锁升级为重量级锁。

升级之后的对象会重 lock_stack 移除。

void LightweightSynchronizer::ensure_lock_stack_space(JavaThread* current) {
  LockStack& lock_stack = current->lock_stack();
  // Make room on lock_stack
  if (lock_stack.is_full()) {
    // Inflate contended objects
    LockStackInflateContendedLocks().inflate(current);
    if (lock_stack.is_full()) {
      // Inflate the oldest object
      inflate_fast_locked_object(lock_stack.bottom(), ObjectSynchronizer::inflate_cause_vm_internal, current, current);
    }
  }
}

锁自旋

当线程获取锁失败时,就会进入自旋状态,循环退出有几个条件:

  1. 对象锁升级为重量级锁。
  2. 线程需要进入安全点。
  3. 达到自旋最大次数。
  4. 获取到轻量级锁,只有获取到轻量级锁返回的是 true。
bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stack, JavaThread* current, bool observed_deflation) {
  // LightweightFastLockingSpins = 13
  const int log_spin_limit = os::is_MP() ? LightweightFastLockingSpins : 1;
  const int log_min_safepoint_check_interval = 10;

  markWord mark = obj->mark();
  const auto should_spin = [&]() {
    if (!mark.has_monitor()) {
      return true;
    } else if (observed_deflation) {/*observed_deflation is false*/ }
    return false;
  };
  // Always attempt to lock once even when safepoint synchronizing.
  bool should_process = false;
  for (int i = 0; should_spin() && !should_process && i < log_spin_limit; i++) {
    // Spin with exponential backoff.
    const int total_spin_count = 1 << i;
    const int inner_spin_count = MIN2(1 << log_min_safepoint_check_interval, total_spin_count);
    const int outer_spin_count = total_spin_count / inner_spin_count;
    for (int outer = 0; outer < outer_spin_count; outer++) {
      should_process = SafepointMechanism::should_process(current);
      if (should_process) { break; }
      for (int inner = 1; inner < inner_spin_count; inner++) { SpinPause(); }
    }
    if (fast_lock_try_enter(obj, lock_stack, current)) return true;
  }
  return false;
}

LightweightFastLockingSpins默认为 13,各个循环变量的次数如下,只有当 i > 10 时,outer_spin_count 代码的循环次数才会增加。

Iteration (i) total_spin_count inner_spin_count outer_spin_count
0 1 1 1
1 2 2 1
2 4 4 1
3 8 8 1
4 16 16 1
5 32 32 1
6 64 64 1
7 128 128 1
8 256 256 1
9 512 512 1
10 1024 1024 1
11 2048 1024 2
12 4096 1024 4

重入锁

当栈顶元素与要获取的对象相同时,则加锁成功。

inline bool LockStack::try_recursive_enter(oop o) {

  int end = to_index(_top);
  if (end == 0 || _base[end - 1] != o) {
    return false;
  }
  _base[end] = o;
  _top += oopSize;
  return true;
}

重量级锁

当对象锁存在竞争时,轻量级就会升级为重量级锁,本小节说的重量级锁是基于 hash table 实现的新版本。

//TODO

实现较为复杂,某些地方需要邮件询问 OpenJDK 的开发者,后续再补充。

总结

本文介绍了 markword 的机构,对比了 Compact Object Headers 前后 synchronized 的实现原理。本文有很多地方没有说清楚,笔者需要邮件询问 OpenJDK 的开发者,后续再补充。