最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - ScheduledExecutorService doesn't work in “try with resources” block - Stack Overflow

programmeradmin0浏览0评论

In my Java 23 project, IntelliJ IDEA soft-complained that I was calling Executors.newScheduledThreadPool(1) “without a 'try'-with-resources statement”. To fix this, I accepted IntelliJ's suggestion to surround it with such a try-with-resources block:

@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));
}

However, this does not work. Here's the console output:

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

Using the ScheduledExecutorService without a try-with-resources block works fine, however:

@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));
}

Here's the console output:

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

Why doesn't the try-with-resources block work?

In my Java 23 project, IntelliJ IDEA soft-complained that I was calling Executors.newScheduledThreadPool(1) “without a 'try'-with-resources statement”. To fix this, I accepted IntelliJ's suggestion to surround it with such a try-with-resources block:

@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));
}

However, this does not work. Here's the console output:

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

Using the ScheduledExecutorService without a try-with-resources block works fine, however:

@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));
}

Here's the console output:

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

Why doesn't the try-with-resources block work?

Share Improve this question asked Mar 3 at 18:43 PixelcodePixelcode 4374 silver badges16 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

You are immediately closing the ScheduledExecutorService when you are using it like you are. The service is close()ed as soon as you exit the try block, and since you are not waiting inside you see nothing.

If you want the same output, then you need to wait inside the try block.

@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);
    } catch(Exception e) {
        LOG.error("testScheduledExecutorService(): Error occurred: {}", e.getMessage(), e);
    }

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

In my Java 23 project, IntelliJ IDEA soft-complained that I was calling Executors.newScheduledThreadPool(1) “without a 'try'-with-resources statement”.

No doubt that diagnostic is based on a general rule that AutoCloseable objects such as ExecutorServices should usually be used in a try-with-resources statement. Wrapping new instances that way ensures that they are in fact closed when no longer needed. IntelliJ surely is not expressing a rule specifically about ScheduledExecutorService.

Why doesn't the try-with-resources block work?

In some cases, it does make sense to wrap a new ExecutorService in a try-with-resources statement. That expresses the idea of creating the ES for the express, limited purpose of running the tasks assigned to it in the try clause, waiting for them to complete, and afterward shutting down the ES.

But a ScheduledExecutorService is a bit different, in that its distinguishing feature is an ability to schedule tasks to be started later. When an SES is closed, all scheduled but unstarted tasks are effectively canceled. They will never be started on account of the SES closure. In your example, control falls out of the try-with-resources statement immediately after your task(s) are scheduled, before any are started, so none ever run. This is try-with-resources working exactly as it should do.

IntelliJ's diagnostic may be overaggressive, but before you say so, consider that your second example has a flaw: it fails to close / shutdown the SES when it has finished with it. This is exactly the problem that a try-with-resources is intended to solve. Just because ExecutorServices are AutoCloseable does not mean that they should always be used in conjunction with try-with-resources, but try-with-resources nevertheless looks like a good fit in your particular case. To make it work as you seem to intend, you should move the Thread.sleep() into the try clause, preventing the SES from being closed prematurely, but nevertheless ensuring that it is closed when you're ready for that:

@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);
    } catch(Exception e) {
        log.error("testScheduledExecutorService(): Error occurred: {}", e.getMessage(), e);
    }

    log.info("Finishing at {}", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
发布评论

评论列表(0)

  1. 暂无评论