登录
首页 >  文章 >  java教程

Java锁插队机制是什么?

时间:2025-12-13 08:09:37 500浏览 收藏

推广推荐
免费电影APP ➜
支持 PC / 移动端,安全直达

一分耕耘,一分收获!既然都打开这篇《Java锁插队机制详解》,就坚持看下去,学下去吧!本文主要会给大家讲到等等知识点,如果大家对本文有好的建议或者看到有不足之处,非常欢迎大家积极提出!在后续文章我会继续更新文章相关的内容,希望对大家都有所帮助!

公平锁禁止插队,非公平锁允许在锁空闲时抢先获取。ReentrantLock(true) 为公平锁,线程必须按AQS队列顺序获取锁,避免饥饿但吞吐较低;默认ReentrantLock()和synchronized为非公平锁,尝试CAS抢锁成功则直接占用,仅在锁释放瞬间可“插队”,并非任意跳过队列。synchronized无公平选项,基于ObjectMonitor实现,notify不保证顺序,新竞争者与唤醒线程公平竞争。ReentrantReadWriteLock默认非公平,写线程可在读队列未获取时抢先,启用公平模式后统一FIFO排队。插队是性能与公平的权衡,合理选型比关注能否插队更重要。

java不同锁模式下的插队探究

Java中锁的“插队”行为,本质上取决于锁的公平性策略和底层实现机制,而不是锁类型本身决定能否插队。公平锁禁止插队,非公平锁允许插队——这是最核心的区分点。

公平锁:严格按等待顺序执行,不许插队

ReentrantLock(true) 创建的公平锁为例,线程获取锁时会先检查同步队列(AQS CLH队列)中是否有前置等待者。如果有,当前线程必须入队排队,不能尝试直接抢占。

  • 即使持有锁的线程刚释放,新来的线程也得老老实实排到队尾
  • 唤醒遵循 FIFO,头节点线程被 unpark,后续依次推进
  • 好处是避免饥饿,坏处是上下文切换多、吞吐量略低

非公平锁:允许“插队”,但仅限于锁空闲时的抢夺

默认的 ReentrantLock()synchronized 都是非公平的。它们在 acquire 流程中会先尝试 CAS 抢锁(tryAcquire),成功就直接占用,无需排队。

  • 这个“插队”只发生在锁刚释放、尚未唤醒等待线程的极短时间窗口内
  • 不是任意时刻都能插,也不是跳过队列中间节点——只是比唤醒+调度更快地抢占了空档
  • 如果锁正被占用,新线程仍需入队;若队列非空,它也不会越过前面的人

synchronized 没有公平选项,但行为接近非公平锁

JVM 对 synchronized 的实现(如偏向锁→轻量级锁→重量级锁)始终采用非公平策略。进入重量级锁后,虽然会用 ObjectMonitor 管理等待队列(_WaitSet),但 notify/notifyAll 唤醒不保证顺序,且新竞争线程可与刚被唤醒的线程再次竞争锁。

  • 没有 API 控制公平性,无法开启公平模式
  • 在高竞争下可能出现某些线程长期得不到锁(相对饥饿),但概率不高
  • 实际表现和 ReentrantLock(false) 类似:快、简单、适合大多数场景

读写锁中的插队逻辑更复杂:写锁可插读队列,但受策略约束

ReentrantReadWriteLock 默认也是非公平的。它的插队规则更精细:

  • 写线程尝试获取写锁时,若读锁已被持有多次,它不能插队——必须等所有读锁释放
  • 但如果读锁已释放、而读线程还在队列里排队,写线程可能抢先获取(即“写插读”)
  • 可启用公平模式(构造时传 true),此时读写线程统一按 FIFO 排队,彻底禁用插队

基本上就这些。插队不是 bug,而是权衡响应速度与公平性的设计选择。用对场景,比纠结“能不能插”更重要。

到这里,我们也就讲完了《Java锁插队机制是什么?》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>