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

SpringBoot中终止此前运行函数并启动新函数的实现方法

问题根因

你当前的代码有两个致命问题:

  1. while(true) 是无任何退出条件的死循环,运行时会一直占用处理/startLog请求的Tomcat工作线程,导致这个请求永远不会返回响应,前端点Start后会一直处于加载状态。
  2. 循环运行在独立的请求线程中,没有共享的控制标记,/stopLog接口被调用时根本没有途径介入终止正在运行的循环。
修复方案

用volatile修饰的布尔值作为全局运行开关,将日志打印逻辑放到独立异步线程中执行,两个接口通过修改这个开关值控制循环启停:

  • 启动接口先判断任务状态,避免重复启动,再把开关置为运行状态,启动异步线程跑循环
  • 循环每次执行前先检查开关状态,开关被置为停止时立刻退出循环
  • 停止接口仅需把全局开关置为停止状态即可
  • 循环内增加固定休眠间隔,避免CPU被占满、日志无限制刷盘

修复后完整代码

package com.springbootLogging.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path="/")
public class AppController {

    private final Logger logger = LoggerFactory.getLogger(AppController.class);
    // volatile保证多线程场景下变量修改的可见性,避免循环线程读不到停止信号
    private volatile boolean logTaskRunning = false;

    @CrossOrigin
    @GetMapping(path="/startLog")
    public String startPrintingLogs() {
        // 重复启动判断,避免多开并行循环
        if (logTaskRunning) {
            return "日志打印任务已在运行中,无需重复启动";
        }
        logTaskRunning = true;
        // 异步线程跑循环,不占用Tomcat请求线程,接口可立刻返回响应
        new Thread(() -> {
            while (logTaskRunning) {
                logger.debug("It is a debug logger.");
                logger.error("It is an error logger.");
                logger.info("It is a info logger.");
                logger.trace("It is a trace logger.");
                logger.warn("It is a warn logger.");
                try {
                    // 打印间隔设为1秒,可按需调整,无间隔会直接占满CPU、刷爆日志
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
        return "日志打印任务启动成功";
    }

    @CrossOrigin
    @GetMapping(path="/stopLog")
    public String stopPrintingLogs() {
        logTaskRunning = false;
        return "日志打印任务已停止";
    }
}
关键注意点
  • 不要省略volatile关键字:HTTP请求由不同的Tomcat工作线程处理,不加volatile的话,运行循环的线程可能因为JVM的线程缓存、指令重排序机制,一直读不到stop接口修改后的开关值,导致停止功能失效。
  • 不要在Controller的请求处理方法里直接写无限循环:Tomcat的工作线程池大小是有限的,直接占住不释放会很快耗尽线程资源,导致所有接口都无法响应。
  • 如果后续需要支持更复杂的异步任务控制,可以直接用Spring自带的@Async注解配合线程池管理,比手动new Thread更规范,适合生产环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:24:30