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

Java中如何停止运行中的线程(异步进程)?附场景与代码示例

解决方案

核心逻辑

  • 用Future对象跟踪所有提交的异步任务,通过Future.cancel(true)触发线程中断
  • 任务内部必须主动检查中断状态,确保能响应终止信号
  • 统一管理任务生命周期,支持超时自动终止、Cron调度防重复、API手动终止三种场景

1. 改造MyJob类,实现任务跟踪与超时控制

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

public class MyJob {
    private final ExecutorService myExecutorService = Executors.newFixedThreadPool(3);
    // 线程安全容器,存储当前运行任务的Future
    private final List<Future<?>> runningTasks = Collections.synchronizedList(new ArrayList<>());

    public void process() {
        Runnable r1 = () -> task1();
        Runnable r2 = () -> task2();
        Runnable r3 = () -> task3();

        List<Runnable> tasks = List.of(r1, r2, r3);
        runAsync(tasks);
    }

    private void task1() {
        try {
            // 业务逻辑中主动检查中断状态
            while (!Thread.currentThread().isInterrupted()) {
                // 替换为实际业务操作
                TimeUnit.SECONDS.sleep(10);
                // 若有IO操作,执行前也需检查中断
                // if (Thread.currentThread().isInterrupted()) break;
            }
        } catch (InterruptedException e) {
            // 重新设置中断状态,确保上层逻辑能感知
            Thread.currentThread().interrupt();
            // 执行终止后的资源清理(如关闭连接、释放文件)
            System.out.println("Task1被中断,已完成清理");
        }
    }

    // task2()、task3()参照task1()实现,添加中断检查逻辑

    private void runAsync(List<Runnable> tasks) {
        // Cron调度时,先终止未完成的旧任务,避免重复执行
        cancelAllTasks();
        
        // 提交任务并保存Future
        for (Runnable task : tasks) {
            Future<?> future = myExecutorService.submit(task);
            runningTasks.add(future);
        }

        // 启动超时监控,这里设置为1小时
        startTimeoutMonitor(60, TimeUnit.MINUTES);
    }

    // 超时自动终止任务
    private void startTimeoutMonitor(long timeout, TimeUnit unit) {
        myExecutorService.submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(unit.toSeconds(timeout));
                cancelAllTasks();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }

    // 统一终止所有运行中的任务
    public void cancelAllTasks() {
        synchronized (runningTasks) {
            for (Future<?> future : runningTasks) {
                // 参数true:向任务线程发送中断信号
                future.cancel(true);
            }
            runningTasks.clear();
        }
    }
}

2. 实现API手动终止端点

以Spring Boot为例,创建控制器暴露终止接口:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JobController {
    private final MyJob myJob;

    public JobController(MyJob myJob) {
        this.myJob = myJob;
    }

    @PostMapping("/api/job/stop")
    public String stopRunningJob() {
        myJob.cancelAllTasks();
        return "所有异步任务已终止";
    }
}

3. Cron调度的适配处理

如果用Spring Scheduler或Quartz做定时调度,每次执行前先清理旧任务:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class JobScheduler {
    private final MyJob myJob;

    public JobScheduler(MyJob myJob) {
        this.myJob = myJob;
    }

    // 示例:每小时执行一次
    @Scheduled(cron = "0 0 * * * ?")
    public void scheduleJob() {
        // 终止未完成的历史任务
        myJob.cancelAllTasks();
        // 启动新任务
        myJob.process();
    }
}

关键注意点

  • 中断响应:阻塞方法(如sleep、IO操作)会抛出InterruptedException,需捕获并处理清理;非阻塞循环必须主动调用Thread.currentThread().isInterrupted()检查状态。
  • 线程安全:操作任务列表时加锁,避免并发修改异常。
  • 资源清理:任务被中断后,必须释放持有的资源(数据库连接、文件句柄等),防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 04:05:40