一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

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

时间:2026-07-09 10:11:12 编辑:袖梨 来源:一聚教程网

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

ReentrantLock 的锁释放顺序本身不直接决定任务调度顺序,真正起作用的是锁的类型(公平 or 非公平)以及线程获取锁时的策略。释放锁只是触发“谁该下一个获得锁”的判断时机,而这个判断逻辑由锁实例的公平性决定,不是由释放动作的先后或顺序控制的。

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

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

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

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

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

  • 刚释放锁的线程,如果马上再次调用 lock(),很可能抢成功(尤其在低竞争时)
  • 等待队列里的线程可能被反复跳过,导致饥饿
  • 实际调度顺序是“抢到算数”,和释放顺序无关,只和抢锁时机、CPU 调度、CAS 成功率有关

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

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

立即学习“Java免费学习笔记(深入)”;

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

实践中要注意的误区

有人误以为“先 unlock 的线程,后续就更容易拿到锁”,这是不成立的。例如:

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

不复杂但容易忽略:锁释放只是门开了,谁进门,得看门上贴的是“排队入场”还是“先到先撞门”。

热门栏目