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

为何ScheduledExecutorService在try-with-resources块中无法正常工作?

为什么try-with-resources块中的ScheduledExecutorService无法正常执行定时任务?

问题场景

在Java 23项目中,IntelliJ IDEA提示调用Executors.newScheduledThreadPool(1)时需使用try-with-resources语句,但将其放入该块后,定时任务完全不执行;不使用try-with-resources时,任务能正常周期性运行。

使用try-with-resources的代码及输出

代码:

@Test
public void testScheduledExecutorServiceTryWithResources() throws InterruptedException {
    Logger LOG = LogManager.getLogger();

    try (ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1)) {
        executorService.scheduleWithFixedDelay(() -> LOG.info("Doing something …"), 0, 1, TimeUnit.SECONDS);
    } catch(Exception e) {
        LOG.error("testScheduledExecutorService(): Error occurred: {}", e.getMessage(), e);
    }

    Thread.sleep(5000);
    LOG.info("Finishing at {}", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}

输出:

Finishing at 2025-03-03T19:38:08.549627875

不使用try-with-resources的代码及输出

代码:

@Test
public void testScheduledExecutorServiceBare() throws InterruptedException {
    Logger LOG = LogManager.getLogger();

    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.scheduleWithFixedDelay(() -> LOG.info("Doing something …"), 0, 1, TimeUnit.SECONDS);

    Thread.sleep(5000);
    LOG.info("Finishing at {}", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}

输出:

Doing something …
Doing something …
Doing something …
Doing something …
Doing something …
Doing something …
Finishing at 2025-03-03T19:30:45.165711955

原因分析

问题核心在于try-with-resources的自动关闭机制:

  • Java 9及以后版本中,ExecutorService实现了AutoCloseable接口,因此可以被try-with-resources管理。
  • try-with-resources块执行完毕后,会自动调用资源的close()方法。对于ScheduledExecutorService而言,close()方法会触发shutdown()操作:这会立即停止接受新任务,同时取消所有未执行的周期性任务,甚至可能终止正在启动的任务。
  • 在你的代码中,try块仅完成了定时任务的提交,代码立刻执行到try块末尾,随后executorService.close()被调用——此时定时任务还没来得及启动(或刚启动就被终止),自然看不到任务执行日志。

解决方法

如果要继续使用try-with-resources,需要确保在try块内等待任务完成执行周期,将Thread.sleep(5000)移至try块内部:

@Test
public void testScheduledExecutorServiceTryWithResources() throws InterruptedException {
    Logger LOG = LogManager.getLogger();

    try (ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1)) {
        executorService.scheduleWithFixedDelay(() -> LOG.info("Doing something …"), 0, 1, TimeUnit.SECONDS);
        Thread.sleep(5000); // 在关闭线程池前等待任务执行
        LOG.info("Finishing at {}", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    } catch(Exception e) {
        LOG.error("testScheduledExecutorService(): Error occurred: {}", e.getMessage(), e);
    }
}

另外需要注意:IDEA的提示仅针对资源关闭的规范,但对于需要长期运行的周期性任务场景,try-with-resources并不适配——除非你明确在块内完成所有任务的执行逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 02:23:25