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

如何用Java的ScheduledThreadPoolExecutor重启终止线程并维持固定线程数?

嘿,我明白你想要的效果——一个固定线程数的“不死”线程池,不管线程是正常跑完还是意外挂掉,都能立刻补一个一模一样的上去,持续输出1-2-3-4循环。你现在代码跑一次就停,核心问题是普通线程池里的线程完成任务后就会终止,不会自动重启,而且如果你的任务本身只执行一次打印,那线程跑完自然就歇菜了。

给你两个可行的解决方案,按需选择:

方案一:让任务本身持续运行(最简单直接)

这种思路是让每个线程的任务变成无限循环,哪怕遇到异常也能继续执行,从根源上避免线程终止。代码示例:

import org.junit.Test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Testing {

    // 定义一个会重复执行的任务
    class RepeatingTask implements Runnable {
        private final int number;

        public RepeatingTask(int number) {
            this.number = number;
        }

        @Override
        public void run() {
            // 只要线程没被主动中断,就一直循环执行
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    System.out.print(number + "-");
                    Thread.sleep(1000); // 模拟任务耗时,可根据需求调整
                } catch (InterruptedException e) {
                    // 捕获中断信号,优雅退出循环
                    Thread.currentThread().interrupt();
                    break;
                } catch (Exception e) {
                    // 捕获其他所有异常,防止线程意外挂掉
                    System.err.println("任务" + number + "出问题了:" + e.getMessage());
                }
            }
        }
    }

    @Test
    public void testPersistentThreadPool() throws InterruptedException {
        int fixedThreadCount = 4;
        ExecutorService executor = Executors.newFixedThreadPool(fixedThreadCount);

        // 提交4个对应数字的任务
        for (int i = 1; i <= fixedThreadCount; i++) {
            executor.submit(new RepeatingTask(i));
        }

        // 让JUnit测试线程一直等待,否则测试结束会杀掉所有线程
        Thread.currentThread().join();
    }
}

这个方案的好处是简单直接,每个线程会一直跑下去,除非被主动中断。就算某个任务抛出异常,也会被捕获,线程不会终止,依然能继续打印数字。

方案二:线程终止时自动补新线程(更灵活)

如果你的任务是一次性的,但希望线程跑完后立刻补一个相同的任务上去(比如任务是周期性执行,但不想用循环),可以自定义线程池,重写afterExecute方法来实现自动补位:

import org.junit.Test;
import java.util.concurrent.*;

public class Testing {

    class RepeatingTask implements Runnable {
        private final int number;

        public RepeatingTask(int number) {
            this.number = number;
        }

        @Override
        public void run() {
            System.out.print(number + "-");
            // 这里可以是你的一次性任务逻辑
        }
    }

    // 自定义线程池,实现线程终止后自动补位
    class ReplacingThreadPool extends ThreadPoolExecutor {
        private final TaskFactory taskFactory;

        public ReplacingThreadPool(int coreSize, TaskFactory factory) {
            super(coreSize, coreSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            this.taskFactory = factory;
        }

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            // 只要线程池没关闭,就提交一个和原任务一样的新任务
            if (!isShutdown()) {
                submit(taskFactory.copyTask(r));
            }
        }
    }

    // 任务复制工厂,用来创建和原任务一模一样的副本
    interface TaskFactory {
        Runnable copyTask(Runnable original);
    }

    @Test
    public void testReplacingThreadPool() throws InterruptedException {
        int fixedThreadCount = 4;
        TaskFactory factory = original -> {
            // 复制原来的RepeatingTask
            if (original instanceof RepeatingTask) {
                return new RepeatingTask(((RepeatingTask) original).number);
            }
            return original;
        };

        ReplacingThreadPool executor = new ReplacingThreadPool(fixedThreadCount, factory);

        // 初始化提交4个任务
        for (int i = 1; i <= fixedThreadCount; i++) {
            executor.submit(new RepeatingTask(i));
        }

        // 让测试线程持续等待
        Thread.currentThread().join();
    }
}

这个方案里,每个任务执行完一次后,线程池会自动创建一个相同的任务提交进去,保证线程数量始终是4个,持续输出1-2-3-4循环。哪怕某个线程因为异常挂了,afterExecute依然会触发,补上新的任务和线程。

为什么你原来的代码会停?

大概率是你的任务只执行了一次打印就结束了,线程池里的线程完成任务后就进入空闲状态,核心线程默认会等待新任务,但你没有继续提交任务,所以整个程序就停了。上面的两种方案要么让任务自己循环跑,要么自动补新任务,就能解决这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:02:52