为何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
相关产品推荐
相关产品推荐

