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

如何捕获运行中Java进程的耗时以触发中间告警

解决方案:不中断主进程的耗时监控与告警记录

核心思路

放弃Future.get(timeout)的中断式超时逻辑,改用独立的监控线程/定时任务,仅读取主进程的运行状态(耗时),不干预主进程执行,实现并发记录告警且不中断主进程的目标。

方案一:独立监控线程+共享状态

通过线程安全的共享状态,让监控线程定时检查主进程耗时,触发告警记录。

主进程任务实现

主进程维护启动时间,并通过原子变量标记任务完成状态:

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;

public class MainProcessTask implements Runnable {
    private final long startTime;
    private final AtomicBoolean isCompleted;

    public MainProcessTask(AtomicBoolean isCompleted) {
        this.startTime = System.currentTimeMillis();
        this.isCompleted = isCompleted;
    }

    @Override
    public void run() {
        try {
            // 模拟随数据量变化的业务处理
            processData();
        } finally {
            // 任务完成时标记状态
            isCompleted.set(true);
        }
    }

    private void processData() {
        // 实际业务逻辑:处理数据(示例为随机时长睡眠)
        try {
            Thread.sleep(new Random().nextInt(30000)); // 0-30秒模拟不同数据量耗时
        } catch (InterruptedException e) {
            // 即使收到中断信号,保留主进程执行(仅恢复中断标记)
            Thread.currentThread().interrupt();
        }
    }

    // 获取当前已运行时长
    public long getElapsedTime() {
        return System.currentTimeMillis() - startTime;
    }
}

监控线程实现

定时检查主进程耗时,达到阈值时记录告警,直到主进程完成:

import java.util.concurrent.atomic.AtomicBoolean;

public class MonitorTask implements Runnable {
    private final MainProcessTask mainTask;
    private final AtomicBoolean isMainCompleted;
    private static final long ALERT_THRESHOLD = 15000; // 告警阈值:15秒
    private static final long CHECK_INTERVAL = 5000;    // 检查间隔:5秒

    public MonitorTask(MainProcessTask mainTask, AtomicBoolean isMainCompleted) {
        this.mainTask = mainTask;
        this.isMainCompleted = isMainCompleted;
    }

    @Override
    public void run() {
        while (!isMainCompleted.get()) {
            long elapsed = mainTask.getElapsedTime();
            if (elapsed > ALERT_THRESHOLD) {
                // 记录告警(可替换为日志框架、告警系统调用)
                System.out.printf("告警:主进程已运行%d毫秒,超过阈值%d毫秒%n", elapsed, ALERT_THRESHOLD);
            }
            try {
                Thread.sleep(CHECK_INTERVAL);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        // 主进程完成后记录最终耗时
        System.out.printf("主进程执行完成,总耗时:%d毫秒%n", mainTask.getElapsedTime());
    }
}

启动代码

import java.util.concurrent.atomic.AtomicBoolean;

public class Main {
    public static void main(String[] args) {
        AtomicBoolean isCompleted = new AtomicBoolean(false);
        MainProcessTask mainTask = new MainProcessTask(isCompleted);

        // 启动主进程线程
        Thread mainThread = new Thread(mainTask);
        mainThread.start();

        // 启动监控线程
        Thread monitorThread = new Thread(new MonitorTask(mainTask, isCompleted));
        monitorThread.start();

        // 等待主进程与监控线程完成
        try {
            mainThread.join();
            monitorThread.interrupt();
            monitorThread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

方案二:ScheduledExecutorService定时监控

利用JDK定时调度器替代手动线程管理,更简洁优雅:

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class ScheduledMonitorExample {
    public static void main(String[] args) {
        AtomicBoolean isCompleted = new AtomicBoolean(false);
        MainProcessTask mainTask = new MainProcessTask(isCompleted);
        long alertThreshold = 15000;

        // 启动主进程
        Thread mainThread = new Thread(mainTask);
        mainThread.start();

        // 创建单线程定时调度器
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

        // 每隔5秒执行一次监控任务(首次执行立即触发)
        ScheduledFuture<?> monitorFuture = scheduler.scheduleAtFixedRate(() -> {
            if (isCompleted.get()) {
                System.out.printf("主进程执行完成,总耗时:%d毫秒%n", mainTask.getElapsedTime());
                monitorFuture.cancel(false); // 取消定时任务
                scheduler.shutdown();
                return;
            }
            long elapsed = mainTask.getElapsedTime();
            if (elapsed > alertThreshold) {
                System.out.printf("告警:主进程已运行%d毫秒,超过阈值%d毫秒%n", elapsed, alertThreshold);
            }
        }, 0, 5, TimeUnit.SECONDS);

        // 等待主进程完成并关闭调度器
        try {
            mainThread.join();
            scheduler.shutdown();
            if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            scheduler.shutdownNow();
        }
    }

    // 复用主进程任务类
    static class MainProcessTask implements Runnable {
        private final long startTime;
        private final AtomicBoolean isCompleted;

        public MainProcessTask(AtomicBoolean isCompleted) {
            this.startTime = System.currentTimeMillis();
            this.isCompleted = isCompleted;
        }

        @Override
        public void run() {
            try {
                processData();
            } finally {
                isCompleted.set(true);
            }
        }

        private void processData() {
            try {
                Thread.sleep(new Random().nextInt(30000));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        public long getElapsedTime() {
            return System.currentTimeMillis() - startTime;
        }
    }
}

关键注意点

  • 线程安全:使用AtomicBoolean标记任务完成状态,避免多线程下的状态不一致;启动时间startTime为不可变变量,天然线程安全。
  • 不中断主进程:监控逻辑仅读取耗时状态,不调用任何中断主进程的方法(如Future.cancel(true)),确保主进程不受干扰。
  • 灵活配置:可根据需求调整告警阈值、检查间隔,告警记录逻辑可替换为日志框架(如SLF4J)、企业告警系统接口等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 21:36:26