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

java.util.Timer任务全部终止后如何正确释放ProcessQueues资源?

解决方案

核心问题是Timer.schedule()为异步调度逻辑,调用后会立即返回,不会等待任务执行结束,导致try-with-resources代码块执行完成后直接触发close(),提前释放资源。你不需要移除AutoCloseable接口实现,按以下方案改造即可:

方案1:替换Timer为ScheduledExecutorService(推荐)

ScheduledExecutorService是JDK官方推荐的定时任务实现,内置优雅关闭和等待任务终止的API,适配现有逻辑的改造成本很低:

  • 改造ProcessQueues类,新增ScheduledExecutorService成员,替换原有Timer
  • 在close()方法中先关闭线程池,等待所有任务终止后再释放MessageQueue资源

示例代码:

import java.util.ArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ProcessQueues implements AutoCloseable {
    private ArrayList<MessageQueue> queueObjects = new ArrayList<>();
    // 按实际任务量调整核心线程数
    private final ScheduledExecutorService monitorExecutor = Executors.newScheduledThreadPool(2);

    public ProcessQueues() {
        queueObjects.add(new FFE_DPVALID_TO_SSP_EXCEPTION());
        queueObjects.add(new FFE_DPVALID_TO_SSP_ESBEXCEPTION());
        // 其余初始化逻辑
    }
    
    private void scheduleProcessRuns() {
        try {
            for (MessageQueue obj : queueObjects) {
                // 对应原有定时调度逻辑,按实际参数调整初始延迟、执行周期、时间单位
                monitorExecutor.scheduleAtFixedRate(obj, 0, 1, TimeUnit.MILLISECONDS);
            }
        } catch (Exception ex) {
            // 原有异常处理逻辑
        }
    }

    public static void main(String[] args) {   
      try (ProcessQueues pq = new ProcessQueues()) {
        pq.scheduleProcessRuns();
        // 可在此处添加额外业务逻辑,比如监听进程停止信号
      } catch (Exception e) {
         // 原有异常处理逻辑
      }
    }

    @Override
    public void close() throws Exception {
        // 1. 停止接收新任务
        monitorExecutor.shutdown();
        // 2. 等待所有已提交任务执行完成,自定义超时时间避免永久阻塞
        if (!monitorExecutor.awaitTermination(60, TimeUnit.MINUTES)) {
            // 超时后强制关闭所有未完成任务
            monitorExecutor.shutdownNow();
            if (!monitorExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                System.err.println("定时任务线程池无法正常终止");
            }
        }
        // 3. 所有任务终止后再释放MessageQueue资源
        for (MessageQueue queue : queueObjects) {
            queue.close();
        }
    }
}

方案2:保留Timer的适配方案

如果必须使用Timer实现,可以通过CountDownLatch跟踪所有任务的完成状态:

  • 给每个MessageQueue任务注入CountDownLatch实例,任务执行到终止逻辑时调用countDown()
  • 在close()方法中调用latch.await()等待所有任务计数归零后再释放资源
    如果是循环执行的定时任务,需要额外设置终止触发条件(比如全局停止标识位),符合条件时再执行countDown逻辑。

注意事项

  • 不要重写finalize()方法,该方法执行时机完全不可控,Java 9开始已经被标记为废弃
  • 如果你的定时任务是永久循环运行的,需要额外增加终止信号监听逻辑,触发后先停止所有任务调度,再进入资源释放流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:39:01