黔南布依族苗族自治州网站建设_网站建设公司_VPS_seo优化
2026/1/16 15:00:43 网站建设 项目流程

本篇博文我将通过对比来深入理解synchronizedReentrantLock在操作系统层面的实现机制。

一、整体对比概览

特性synchronizedReentrantLock
底层原语Monitor(JVM内置) + 互斥锁AQS(AbstractQueuedSynchronizer) + 互斥锁
最终系统调用futex(Linux)或类似futex(Linux)或类似
阻塞实现内核态阻塞队列内核态阻塞队列
公平性非公平(JVM实现决定)可选公平/非公平
性能差异来源JVM优化(锁升级)算法优化(CAS自旋策略)

二、底层实现架构对比

1.synchronized的实现栈

Java synchronized代码 ↓ JVM的ObjectMonitor(C++实现) ↓ os::PlatformMonitor(平台相关封装) ↓ pthread_mutex_t / futex(Linux) ↓ sys_futex系统调用 ↓ 内核调度器管理线程阻塞队列

2.ReentrantLock的实现栈

Java ReentrantLock.lock() ↓ AbstractQueuedSynchronizer.acquire(1) ↓ tryAcquire() ← FairSync/NonfairSync ↓ Unsafe.compareAndSwapInt()(CAS) ↓ 如果CAS失败→LockSupport.park() ↓ sun.misc.Unsafe.park() ↓ pthread_cond_wait / futex(Linux) ↓ sys_futex系统调用

三、关键差异分析

1.锁获取策略不同

synchronized(默认非公平):

// JVM的ObjectMonitor::enter代码逻辑(伪代码)voidObjectMonitor::enter(Thread*self){// 1. 直接尝试CAS获取(非公平)if(CAS(&_owner,NULL,self))return;// 2. 检查重入if(self==_owner){_recursions++;return;}// 3. 自旋尝试(自适应自旋)if(TrySpin(self))return;// 4. 进入重量级锁EnterI(self);// 调用系统futex}

ReentrantLock.NonfairSync:

// AQS的非公平获取逻辑finalvoidlock(){if(compareAndSetState(0,1))// 直接插队尝试setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);// 非公平尝试}

ReentrantLock.FairSync(公平锁):

protectedfinalbooleantryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();if(c==0){// 关键区别:先检查队列是否有等待者if(!hasQueuedPredecessors()&&// 检查等待队列compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}// ... 重入逻辑}

2.阻塞/唤醒机制对比

synchronized的阻塞:

// ObjectMonitor::EnterI 中的阻塞(HotSpot源码) void ObjectMonitor::EnterI(Thread* self) { // 将线程加入_cxq(竞争队列) // ... for (;;) { if (TryLock(self) > 0) break; // 最终调用os::PlatformEvent::park() park(); // 调用pthread_cond_wait或futex } }

ReentrantLock的阻塞:

// LockSupport.park()最终调用publicstaticvoidpark(){UNSAFE.park(false,0L);}// HotSpot中的Unsafe.park实现voidParker::park(bool isAbsolute,jlong time){// 使用pthread_cond_t条件变量pthread_cond_wait(&_cond,&_mutex);}

3.操作系统层面的相同本质

实际上,两者在重量级竞争时都会使用相同的系统调用

// Linux下两者的最终系统调用都是futex// 1. synchronized的阻塞syscall(SYS_futex,uaddr,FUTEX_WAIT,val,timeout,uaddr2,val3);// 2. ReentrantLock的阻塞(通过pthread实现)// pthread_mutex_lock -> futex_wait// pthread_cond_wait -> futex_wait

四、性能差异的真正原因

1.锁升级 vs 直接CAS

// synchronized:可能经过锁升级// 偏向锁 → 轻量级锁 → 重量级锁(开销递增)// ReentrantLock:直接CAS尝试// CAS成功:直接获取(用户态)// CAS失败:可能自旋后进入AQS队列

2.自旋策略不同

// synchronized:自适应自旋// - 根据上次自旋是否成功调整下次自旋时间// - JVM参数:-XX:+UseSpinning -XX:PreBlockSpin// ReentrantLock:可控的自旋// 在进入队列前可能自旋,但策略更保守

3.AQS的队列优化

// AQS的CLH队列变体(虚拟队列)// 每个节点通过前驱节点的状态判断是否该唤醒// 减少不必要的唤醒(对比synchronized的随机唤醒)privatevoidunparkSuccessor(Nodenode){// 从尾向前找最前面的有效节点// 避免"惊群效应"}

五、实际系统调用跟踪

使用strace跟踪两种锁的系统调用:

# synchronized的典型调用futex(0x7f8b380008c8, FUTEX_WAIT_PRIVATE,1, NULL)=0futex(0x7f8b380008c8, FUTEX_WAKE_PRIVATE,1)=1# ReentrantLock的典型调用futex(0x7f8b38000900, FUTEX_WAIT_BITSET_PRIVATE,2, NULL, ffffffff)=0futex(0x7f8b38000900, FUTEX_WAKE_BITSET_PRIVATE,1, NULL, ffffffff)=1

六、选择建议

使用synchronized的情况:

  1. 简单的同步场景
  2. 锁竞争不激烈
  3. 需要JVM内置优化(锁升级)
  4. 代码简洁性优先

使用ReentrantLock的情况:

  1. 需要公平锁
  2. 需要tryLock()、lockInterruptibly()等高级功能
  3. 竞争激烈且临界区执行时间长
  4. 需要条件变量(Condition)的精细控制

七、总结

维度synchronizedReentrantLock
OS层面相同(最终都是futex)相同(最终都是futex)
用户态优化锁升级(偏向/轻量级/重量级)AQS队列+CAS自旋
公平性非公平(实现决定)可选择
功能基础丰富(可中断、超时、条件等)
性能低竞争时更优高竞争时可能更优

核心结论

  1. 两者的操作系统底层机制本质相同,都是基于互斥锁和条件变量
  2. 性能差异主要来自用户态的实现策略(锁升级 vs AQS)
  3. synchronized更适合简单场景,依赖JVM优化
  4. ReentrantLock提供更多控制和可预测性

这解释了为什么在低竞争时synchronized可能更快(得益于锁升级),而在高竞争时ReentrantLock可能表现更好(更灵活的CAS和队列管理)。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询