从一道面试题开始:如何让同时启动的线程按顺序执行?

最近准备面试刷题,遇到一个多线程问题:如何让 A、B、C 三个线程同时启动 ,却要按顺序先后执行(A -> B -> C)。

直觉上,"同时启动"意味着线程调度权交给操作系统,执行顺序理应不确定。那如何控制顺序?若让后一个线程等待前一个执行完毕,似乎又违背了"同时启动"的要求。

最初尝试 Thread.join():让 B 等待 A 执行完,C 等待 B 执行完,再按顺序启动它们。但很快发现问题------如果 B 和 C 的初始化逻辑依赖 A 对象,它们甚至无法在 A 启动前被创建。这本质上只是"顺序启动",而非题目要求的"同时启动但顺序执行"。

理解关键点:

  • start() 仅通知系统线程就绪,run() 方法内的逻辑何时执行取决于 CPU 调度。
  • "启动"是状态,"执行"是动作,"等待"是一种阻塞状态。
  • 核心在于控制 run() 方法中关键逻辑的执行顺序,而非启动顺序本身。

使用 CountDownLatch 实现: CountDownLatch 是一个类似发令枪的同步工具。其核心是一个计数器:初始化设定计数值,线程调用 await() 阻塞等待;其他线程完成任务后调用 countDown() 减 1;当计数器归零,所有等待线程被唤醒继续执行。

利用两个 CountDownLatch:一个控制 B 等待 A 完成,一个控制 C 等待 B 完成。

java 复制代码
public class ThreadOrder {
    public static void main(String[] args) {
        // 控制B等待A的信号
        CountDownLatch latchBwaitsA = new CountDownLatch(1);
        // 控制C等待B的信号
        CountDownLatch latchCwaitsB = new CountDownLatch(1);

        Thread a = new Thread(() -> {
            System.out.println("A starts");
            latchBwaitsA.countDown(); // A执行完毕,释放B线程的阻塞
        });

        Thread b = new Thread(() -> {
            try {
                latchBwaitsA.await(); // B等待A完成信号
                System.out.println("B starts");
                latchCwaitsB.countDown(); // B执行完毕,释放C线程的阻塞
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread c = new Thread(() -> {
            try {
                latchCwaitsB.await(); // C等待B完成信号
                System.out.println("C starts");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 真正的"同时启动"
        a.start();
        b.start();
        c.start();
    }
}

输出结果:

复制代码
A starts
B starts
C starts

最关键的是,三个线程的 start() 方法几乎在同一时刻被调用,满足了"同时启动"的要求;而 run() 方法中关键逻辑的执行顺序(打印语句)则通过 CountDownLatch 实现了严格的 A -> B -> C 顺序,没有破坏"同时启动"的前提。

相关推荐
派大鑫wink10 小时前
【Day34】Servlet 进阶:会话管理(Cookie vs Session)
java·开发语言·学习方法
多米Domi01111 小时前
0x3f 第35天 电脑硬盘坏了 +二叉树直径,将有序数组转换为二叉搜索树
java·数据结构·python·算法·leetcode·链表
猫天意11 小时前
【深度学习小课堂】| torch | 升维打击还是原位拼接?深度解码 PyTorch 中 stack 与 cat 的几何奥义
开发语言·人工智能·pytorch·深度学习·神经网络·yolo·机器学习
zqmattack11 小时前
SQL优化与索引策略实战指南
java·数据库·sql
crossaspeed11 小时前
Java-线程池(八股)
java·开发语言
带刺的坐椅11 小时前
又一个项级的 Java Multi Agent 开源项目
java·ai·agent·solon·智能体
Voyager_411 小时前
StringRedisTemplate 和 RedisTemplate 的区别是什么?
java·spring boot
杏花春雨江南11 小时前
JavaWeb企业级项目实战:从SSH到SSM演进 + MQ/Redis/ES高可用架构落地全复盘(实战干货+避坑指南)
java·jvm·spring
UR的出不克12 小时前
使用 Python 爬取 Bilibili 弹幕数据并导出 Excel
java·python·excel
niaiheni12 小时前
PHP文件包含
开发语言·php