目录
[LeetCode 1114. 按序打印:多线程顺序控制的核心逻辑(附完整代码)](#LeetCode 1114. 按序打印:多线程顺序控制的核心逻辑(附完整代码))
[二、解题核心思路:锁 + 标志位 + 线程通信](#二、解题核心思路:锁 + 标志位 + 线程通信)
LeetCode 1114. 按序打印:多线程顺序控制的核心逻辑(附完整代码)
最近练习了 LeetCode 的「按序打印」问题,正好借此梳理多线程顺序控制的核心思路 ------ 这是并发编程的基础考点,分享给刚学 JUC 的朋友~
一、题目核心需求
实现一个Foo类,让三个线程分别调用first()、second()、third(),严格按first→second→third的顺序打印(即使线程启动顺序打乱)。
二、解题核心思路:锁 + 标志位 + 线程通信
要让多线程按固定顺序执行,核心是 **"控制前置方法的执行状态"**,这里用「synchronized锁 + 布尔标志位 + wait/notifyAll通信」实现:
- 标志位 :用
firsttest、secondtest标记 "前序方法是否执行完成"; - 专属锁对象 :创建
private final Object lock作为同步锁(避免外部干扰); - 线程通信 :用
lock.wait()让线程等待(释放锁),lock.notifyAll()唤醒后续线程。
三、完整代码实现
class Foo {
// 标志位:标记前序方法是否执行完成
private boolean firsttest = false;
private boolean secondtest = false;
// 专属锁对象:保证锁的封闭性和唯一性
private final Object lock = new Object();
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
synchronized (lock) {
// 执行first逻辑
printFirst.run();
// 标记first已完成
firsttest = true;
// 唤醒等待lock的线程(second/third)
lock.notifyAll();
}
}
public void second(Runnable printSecond) throws InterruptedException {
synchronized (lock) {
// 循环等待:直到first执行完成(防止虚假唤醒)
while (!firsttest) {
lock.wait();
}
// 执行second逻辑
printSecond.run();
// 标记second已完成
secondtest = true;
// 唤醒等待lock的线程(third)
lock.notifyAll();
}
}
public void third(Runnable printThird) throws InterruptedException {
synchronized (lock) {
// 循环等待:直到second执行完成
while (!secondtest) {
lock.wait();
}
// 执行third逻辑
printThird.run();
}
}
}
四、关键知识点总结
-
专属锁对象的设计 用
private final Object lock而不是this:private:避免外部代码滥用锁;final:防止锁对象被意外替换;Object:轻量化,仅用其 "对象身份" 做锁。
-
为什么用
while而不是if判断标志位? 防止虚假唤醒 (线程可能无原因被唤醒),while会二次检查标志位,确保只有前序方法执行完才继续。 -
wait/notifyAll的作用lock.wait():释放锁,让前序线程执行;lock.notifyAll():唤醒所有等待该锁的线程,传递 "前序已完成" 的信号。