为了账号安全,请及时绑定邮箱和手机立即绑定

Java ExecutorService 使用

Java ExecutorService 使用

繁星淼淼 2021-09-03 17:29:37
我想制作一个 2 线程应用程序,如下所示:创建2个线程池在 #1 线程上运行 foo 方法等待 2 秒在 #2 线程上运行 bar 方法2 个线程池最多应等待 20 秒ExecutorService executor = Executors.newFixedThreadPool(2);executor.submit(() -> foo());executor.awaitTermination(2, TimeUnit.SECONDS);executor.submit(() -> bar());if (!executor.awaitTermination(20, TimeUnit.SECONDS))    executor.shutdownNow();它不起作用,有什么问题?
查看完整描述

2 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

好问题!我不认为你对awaitTermination()方法有清楚的了解。让我们来看看这个文件。


阻塞直到所有任务在关闭请求后完成执行,或发生超时,或当前线程被中断,以先发生者为准。


本awaitTermination()不应该被用于等待所有任务完成。如果这是您正在寻找的语义,请使用invokeAll()阻塞直到所有任务完成。利用awaitTermination() 没有事先shutdown()不当,可能会导致您等待一段时间,由于awaitTermination没有关闭执行人。


在这种情况下,您只是试图强制应用程序等待您的线程完成,但如果它不在您分配的时间范围内,您希望继续。这个特定的案例让我对多线程的使用产生了一些质疑,因为它看起来有点过度设计,但出于教育目的,让我们解释一下如何做到这一点。


基本解决方案


ExecutorService executor = Executors.newFixedThreadPool(2);

executor.submit(() -> foo());

// Thread.sleep(2000); // Wait for 2 seconds

TimeUnit.SECONDS.sleep(2); // Also waits for 2 seconds and a bit more readable

executor.submit(() -> bar());

if (!executor.awaitTermination(20, TimeUnit.SECONDS))

    executor.shutdownNow();

虽然这不是理想的代码,但它会给你你正在寻找的语义。


改进


该executor.submit()会返回一个Future<T>对象。这是 Java 中一个非常强大的对象,并且具有很多功能。让我们看看如何改进场景。


ExecutorService executor = Executors.newFixedThreadPool(2);

Future<T> foo = executor.submit(() -> foo());

T result = foo.get(2, TimeUnit.SECONDS); // Attempt to grab the result for 2 seconds, then move on

executor.submit(() -> bar());

if (!executor.awaitTermination(20, TimeUnit.SECONDS))

    executor.shutdownNow();

现在,这是更合适的代码,并且会以更好的代码结构为您提供所需的语义。此外,如果第一个未来在 2 秒之前完成,它将提前解锁,这是对基本解决方案的一点改进!


正确关机


假设您想等待 20 秒executor以完成,以下是您可以做的额外改进。使用以下代码进行关闭,因为它来自ExecutorService作为关闭示例的文档。在这里,我已将您的等待时间更新为 20 秒。


pool.shutdown(); // Disable new tasks from being submitted

try {

    // Wait a while for existing tasks to terminate

    if (!pool.awaitTermination(20, TimeUnit.SECONDS)) {

      pool.shutdownNow(); // Cancel currently executing tasks

      // Wait a while for tasks to respond to being cancelled

      if (!pool.awaitTermination(20, TimeUnit.SECONDS))

          System.err.println("Pool did not terminate");

    }

} catch (InterruptedException ie) {

    // (Re-)Cancel if current thread also interrupted

    pool.shutdownNow();

    // Preserve interrupt status

    Thread.currentThread().interrupt();

}


查看完整回答
反对 回复 2021-09-03
?
慕勒3428872

TA贡献1848条经验 获得超6个赞

使用预定的执行程序服务怎么样?你想运行任务 a,你想运行任务 b,你想在 20 秒后关闭执行程序服务。


ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

Future<?> futureA = service.submit(()->foo());

ScheduledFuture<?> futureB = service.schedule(()->bar(), 2, TimeUnit.SECONDS);

不知道为什么要关闭执行器,但是可以使用future来等待任务的完成。


Object b = futureB.get(20, TimeUnit.SECONDS);

service.shutdown();


查看完整回答
反对 回复 2021-09-03
  • 2 回答
  • 0 关注
  • 202 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信