You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程:如何实现线程按顺序单次执行run方法后循环执行?

实现按顺序循环执行的多线程协作机制

这种让每个动作对应独立线程、按固定顺序循环执行的需求,本质是要解决多线程间的顺序同步+轮次循环问题。我给你设计一个SequentialCycleCoordinator类来做全局调度,配合每个动作线程就能完美实现你的想法。

核心设计思路

我们需要两个关键同步组件来实现这个机制:

  • CountDownLatch:控制每个步骤的执行时机,确保只有前一个步骤完成后,下一个步骤的线程才能启动。
  • CyclicBarrier:当所有线程完成一轮动作后,统一重置状态,开启下一轮循环。

完整实现代码

协调器类 SequentialCycleCoordinator

这个类负责管理步骤顺序和轮次切换,是整个机制的核心:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

public class SequentialCycleCoordinator {
    // 当前执行的步骤序号(从0开始)
    private final AtomicInteger currentStep = new AtomicInteger(0);
    // 总动作数量
    private final int totalSteps;
    // 等待所有线程完成一轮的屏障,完成后触发重置逻辑
    private final CyclicBarrier roundBarrier;
    // 每个步骤对应的 latch,控制该步骤线程的执行时机
    private final CountDownLatch[] stepLatches;

    public SequentialCycleCoordinator(int totalSteps) {
        this.totalSteps = totalSteps;
        this.roundBarrier = new CyclicBarrier(totalSteps, this::resetForNextRound);
        this.stepLatches = new CountDownLatch[totalSteps];
        
        // 初始化所有步骤的 latch
        for (int i = 0; i < totalSteps; i++) {
            stepLatches[i] = new CountDownLatch(1);
        }
        // 第一个步骤默认放行,启动第一轮
        stepLatches[0].countDown();
    }

    // 让当前线程等待,直到轮到自己的步骤执行
    public void awaitTurn(int stepIndex) throws InterruptedException {
        stepLatches[stepIndex].await();
    }

    // 当前步骤执行完成,通知下一个步骤或等待一轮结束
    public void signalNextStep(int stepIndex) {
        int nextStep = (stepIndex + 1) % totalSteps;
        
        // 如果是最后一步,先等所有线程到屏障,再触发重置
        if (stepIndex == totalSteps - 1) {
            try {
                roundBarrier.await();
            } catch (Exception e) {
                Thread.currentThread().interrupt(); // 中断异常时标记线程中断状态
            }
        } else {
            // 非最后一步,直接放行下一个步骤
            stepLatches[nextStep].countDown();
        }
    }

    // 一轮完成后,重置所有状态,准备下一轮循环
    private void resetForNextRound() {
        currentStep.set(0);
        // 重新初始化所有 latch,并放行第一个步骤
        for (int i = 0; i < totalSteps; i++) {
            stepLatches[i] = new CountDownLatch(1);
        }
        stepLatches[0].countDown();
    }
}

动作线程类 ActionThread

每个动作对应一个线程,通过协调器控制自己的执行时机:

public class ActionThread extends Thread {
    private final int stepIndex; // 当前线程对应的步骤序号
    private final SequentialCycleCoordinator coordinator;
    private final Runnable action; // 要执行的动作逻辑

    public ActionThread(int stepIndex, SequentialCycleCoordinator coordinator, Runnable action) {
        this.stepIndex = stepIndex;
        this.coordinator = coordinator;
        this.action = action;
    }

    @Override
    public void run() {
        try {
            // 循环执行,直到线程被中断
            while (!Thread.currentThread().isInterrupted()) {
                // 等待协调器通知自己可以执行
                coordinator.awaitTurn(stepIndex);
                // 执行具体动作
                action.run();
                // 通知协调器当前步骤完成,触发下一步或等待一轮结束
                coordinator.signalNextStep(stepIndex);
            }
        } catch (InterruptedException e) {
            // 捕获中断,标记线程状态,优雅退出
            Thread.currentThread().interrupt();
            System.out.println("动作线程" + stepIndex + "已中断退出");
        }
    }
}

使用示例

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int totalActions = 3; // 假设有3个按顺序执行的动作
        SequentialCycleCoordinator coordinator = new SequentialCycleCoordinator(totalActions);

        // 创建并启动每个动作线程
        new ActionThread(0, coordinator, () -> {
            System.out.println("执行动作1 | 线程:" + Thread.currentThread().getName());
            try { Thread.sleep(500); } catch (InterruptedException ignored) {} // 模拟动作耗时
        }).start();

        new ActionThread(1, coordinator, () -> {
            System.out.println("执行动作2 | 线程:" + Thread.currentThread().getName());
            try { Thread.sleep(300); } catch (InterruptedException ignored) {}
        }).start();

        new ActionThread(2, coordinator, () -> {
            System.out.println("执行动作3 | 线程:" + Thread.currentThread().getName());
            try { Thread.sleep(400); } catch (InterruptedException ignored) {}
        }).start();

        // 让程序运行10秒后中断所有线程
        Thread.sleep(10000);
        Thread.getAllStackTraces().keySet().stream()
                .filter(t -> t.getName().startsWith("Thread-"))
                .forEach(Thread::interrupt);
    }
}

关键逻辑解释

  1. 步骤顺序控制:每个线程通过awaitTurn等待自己的步骤latch被放行,只有前一个步骤执行完成后,才会调用signalNextStep放行下一个步骤的latch,严格保证顺序。
  2. 轮次循环:当最后一个步骤完成后,会触发CyclicBarrier的等待逻辑,等所有线程都到达屏障后,调用resetForNextRound重置所有latch,放行第一个步骤,开启新的一轮。
  3. 线程安全:使用AtomicInteger管理当前步骤序号,CountDownLatch和CyclicBarrier都是线程安全的同步组件,确保多线程环境下的顺序正确性。

注意事项

  • 记得处理InterruptedException,保证线程可以优雅退出,避免资源泄漏。
  • 如果你的动作可能抛出异常,建议在action.run()外围增加try-catch,避免单个线程异常导致整个循环中断。
  • 可以根据需求扩展协调器,比如添加超时等待、暂停/继续功能等。

内容的提问来源于stack exchange,提问作者StefanoN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:32:57