使用虚拟线程工厂时应用程序关闭

问题描述 投票:0回答:1

我拥有这种平静的代码

public static void main(String[] args){

  ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(Thread.ofVirtual().factory());

  executor.scheduleWithFixedDelay(() -> System.out.println("A"), 0, 1000, TimeUnit.MILLISECONDS);
  executor.scheduleWithFixedDelay(() -> System.out.println("B"), 0, 1, TimeUnit.MINUTES);

}

当我运行此代码时,应用程序立即关闭并显示代码 0。

但是,如果我在没有虚拟工厂的情况下使用

Executors.newSingleThreadScheduledExecutor();
,应用程序将不再关闭,并且计划的线程将无限运行。

java threadpool virtual-threads
1个回答
0
投票

ScheduledExecutorService executor =

名字不好听。 Executor 是

ExecutorService
ScheduledExecutorService
的非常有限的超级接口。我建议使用更具体的名称。

Executors.newSingleThreadScheduledExecutor(Thread.ofVirtual().factory());

该方法不带参数。

更改为:

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;

您的

main
方法的其余部分安排执行两个任务。但随后你的
main
方法就结束了。这意味着您的应用程序退出/退出。这些线程可能会无限期地存在,就像僵尸一样🧟u200d♂️。

要正确关闭您的执行器服务:

  • 使用提供给您的样板代码Javadoc
  • 或者调用
    close
    方法,其实现与样板代码非常接近。
  • 或者,最简单的是,使用 Java 的 try-with-resources 语法。

当涉及计划执行器服务时,try-with-resources 方法与您的代码具有相同的问题。计划重复运行的任务永远不会结束。所以

ScheduledExecutorService
会立即结束,并退出try-with-resources。解决方案是等待一段时间,以便后台线程有机会执行其任务。在下面的代码中,我们休眠五分钟以允许任务运行几次。

// BEWARE! Output from `System.out` may *NOT* appear on the console in chronological order when called across threads.
// Either replace with a proper logging facility, or include and study a timestamp on each line.
System.out.println( "INFO - main method starting. " + Instant.now( ) );
try (
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( ) ;
)
{
    scheduledExecutorService.scheduleWithFixedDelay( ( ) -> System.out.println( "A " + Instant.now( ) ) , 0 , 30 , TimeUnit.SECONDS );
    scheduledExecutorService.scheduleWithFixedDelay( ( ) -> System.out.println( "B " + Instant.now( ) ) , 0 , 1 , TimeUnit.MINUTES );
    try { Thread.sleep( Duration.ofMinutes( 5 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
}
System.out.println( "INFO - main method ending. " + Instant.now( ) );

运行时:

INFO - main method starting. 2024-04-13T05:25:00.553294Z
A 2024-04-13T05:25:00.558754Z
B 2024-04-13T05:25:00.558865Z
A 2024-04-13T05:25:30.564380Z
B 2024-04-13T05:26:00.562910Z
A 2024-04-13T05:26:00.565564Z
A 2024-04-13T05:26:30.570950Z
B 2024-04-13T05:27:00.564144Z
A 2024-04-13T05:27:00.571889Z
A 2024-04-13T05:27:30.576770Z
B 2024-04-13T05:28:00.569514Z
A 2024-04-13T05:28:00.579605Z
A 2024-04-13T05:28:30.585476Z
B 2024-04-13T05:29:00.575518Z
A 2024-04-13T05:29:00.588504Z
A 2024-04-13T05:29:30.591546Z
INFO - main method ending. 2024-04-13T05:30:00.568511Z
© www.soinside.com 2019 - 2024. All rights reserved.