ReentrantLock 怎么让线程排队、怎么唤醒下一个?这篇不看源码讲解,直接用反射读 AQS 的 state 和队列节点,再用公平锁与非公平锁做对照(两种锁的耗时差别已有专门的文章)。
初始 state = 0,队列 = main 加锁一次后 state = 1 main 重入第二次后 state = 2 3 个线程依次排队后(每个间隔 80ms): 队列 = [哨兵 status=0] → [T1 status=1] → [T2 status=1] → [T3 status=1] getQueueLength() = 3;T1 的状态 = WAITING T1 的栈顶:Unsafe.park ← LockSupport.park ← AbstractQueuedSynchronizer.acquire ← AbstractQueuedSynchronizer.acquire main 第一次 unlock 后 state = 1(还持有一次,队列里的线程不会被唤醒) T1 仍然是 WAITING main 完全释放后,三个线程获得锁的顺序 = [T1, T2, T3] 全部结束后 state = 0,队列 = [哨兵 status=0]
反射读内部字段需要 --add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED;字段名(state、head、waiter、status)是 JDK 21 的实现细节。
非公平锁:4 个线程依次排队,释放后按排队顺序拿到锁的轮数 = 30 / 30 公平锁:4 个线程依次排队,释放后按排队顺序拿到锁的轮数 = 30 / 30
非公平锁 tryLock():unlock 之后立刻再拿,成功(插队) 31 次 公平锁 tryLock():unlock 之后立刻再拿,成功(插队) 7 次 公平锁 tryLock(0, SECONDS):unlock 之后立刻再拿,成功(插队) 1 次