商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Java 中 ReentrantLock 锁释放顺序对任务调度的影响

Java 中 ReentrantLock 锁释放顺序对任务调度的影响

  发布于2026-07-08 阅读(0)

扫一扫,手机访问

ReentrantLock的锁释放顺序不决定调度顺序,真正起作用的是锁的公平性:公平锁严格按等待队列FIFO唤醒;非公平锁允许新线程插队抢占,释放仅是竞争机会窗口。

Ja va 中 ReentrantLock 锁释放顺序对任务调度的影响

很多人在接触并发编程时,都有一个下意识的假设:先释放锁的线程,下次就更容易拿到锁。但现实远比想象中复杂——锁释放的顺序本身根本不会决定“谁下一个上场”,真正拍板的,是锁的类型和它的抢锁策略。释放锁这个动作,只是给系统一个信号:“机会窗口开了”,至于轮到谁,得看这把锁是“讲规矩”还是“拼手速”。

公平锁:释放后严格按等待队列顺序唤醒

公平锁在调用 unlock() 时,会从 AQS 同步队列头部取出最早等待的线程(FIFO),并让它尝试获取锁。这意味着:

  • 线程进入等待队列的顺序,就是将来被唤醒的顺序——说话算话。
  • 即使某个线程刚释放锁,它也不能插队重新抢锁;必须老老实实排到队尾重新等待。
  • 不会出现“刚释放就立刻重入”这种低延迟抢占,所有新请求都乖乖排队。

可以这么理解:公平锁就像电影院门口排好的队伍,你出去上个厕所再回来,不好意思,得重新排到队尾。

非公平锁:释放后允许新线程“插队”竞争

非公平锁的 unlock() 只是唤醒等待队列中的一个线程(通常是头节点),但与此同时,任何新调用 lock() 的线程都会直接尝试 CAS 抢占锁——完全不管队列里有没有人等着。所以:

  • 刚释放锁的线程,如果马上再次调用 lock(),很可能抢成功,尤其在低竞争时。这就好比一个人刚从座位上起来,屁股还没离开凳子就又坐了下去。
  • 等待队列里的线程可能被反复跳过,导致饥饿——典型的“后来者先得”。
  • 实际调度顺序是“抢到算数”,和释放顺序无关,只和抢锁的时机、CPU 调度、CAS 成功率有关。

释放顺序 ≠ 执行顺序,更不等于调度优先级

多个线程依次调用 unlock(),并不会形成某种“释放队列”来影响后续调度。JVM 线程调度器根本不感知 unlock 的调用顺序,AQS 也不记录“谁先释放”。关键区别只有两点:

  • 公平锁:唤醒固定为队首线程,释放动作只是触发点。
  • 非公平锁:唤醒 + 允许新线程无条件竞争,释放动作只是潜在机会窗口之一。

所以,不要天真地以为“我早点释放锁,后面就能占便宜”。时机和模式才是真正的裁判。

实践中要注意的误区

有人误以为“先 unlock 的线程,后续就更容易拿到锁”,这其实是一种错觉。来看几个例子:

  • 线程 A 释放锁后立刻 sleep(1),线程 B 此时调用 lock(),大概率抢到——这不是因为 B “后释放”,而是因为它“先抢”。
  • 公平锁下,即使线程 C 比 D 早 1 微秒调用 unlock(),也不会让 C 在下次 lock() 中获得优先权;它仍要和其他等待者一起排队。
  • 锁释放后的调度结果,取决于当前是否有线程正在调用 lock(),以及锁的公平模式,而不是释放动作本身的顺序。

不复杂但容易忽略:锁释放只是门开了,谁进门,得看门上贴的是“排队入场”还是“先到先撞门”。理解这一点,才能在实际调优时避免踩坑。

本文转载于:https://www.php.cn/faq/2787950.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注