掌握 ExecutorService 关闭:跟踪线程池终止
假设您想要执行一些任务。由于通过单个线程执行它可能需要相当长的时间才能获得结果,因此您决定使用可靠的 ExecutorService 通过多个线程处理它。
这是一个示例:
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 5; i++) { int temp = i; executorService.submit(() -> { task(temp); }); } executorService.shutdown(); System.out.println("ExecutorService is shutdown"); } private static void task(int temp) { try { TimeUnit.SECONDS.sleep(1L); System.out.println("Task " + temp + " completed"); } catch (InterruptedException e) { throw new RuntimeException(e); } }
当然,像往常一样,如果不使用“睡眠”作为任务执行的原型,任何线程示例都是不完整的。
它输出,
ExecutorService is shutdown Task 1 completed Task 2 completed Task 0 completed Task 4 completed Task 3 completed
现在想象一下有一个无穷无尽的任务队列,而你不知道其中的数量。也许它们是由数据库中动态添加的条目数量决定的。
例如,一家银行,它必须全天处理大量交易。交易结束时间为下午5点,超过该时间将不再接受任何额外任务。
但是,您确实知道任务的数量是有限的,并且将在某个时间点结束。
如何知道所有任务完成的时间点?
如果您注意到上面的代码片段,ExecutorService.shutdown() 会使主线程立即退出,但后台线程仍然处理已接受的任务直至完成。有什么方法可以让您收到完成通知吗?
我想到了几个解决方案:
- 使用 CountDownLatch 来计算任务 - 但由于您不知道任务的数量,所以使用它是不切实际的。
- 使用ExecutorService.awaitTermination()。然而,这里的时间仍然是不确定的。您可以使用非常自由的 ExecutorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS) 或类似的东西。但这又是一个阻塞调用。
有更好的方法来解决这个问题吗?
Java 确实提供了一种更好且相对未知的方法来解决这个问题。这里的“技巧”是要知道 Executors.newFixedThreadPool 本质上是一个具有预定义值的 ThreadPoolExecutor。我们来看看 Executors.newFixedThreadPool 的实现。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
我真的建议阅读这里的 ThreadPoolExecutor 文档。 ExecutorService 是 ThreadPoolExecutor 的便捷包装。
...强烈建议程序员使用更方便的Executors工厂方法Executors.newCachedThreadPool()(无界线程池,具有自动线程回收功能)、Executors.newFixedThreadPool(int)(固定大小线程池)和Executors.newSingleThreadExecutor( )(单后台线程),为最常见的使用场景预配置设置。
将帮助我们解决问题的部分是:
钩子方法
此类提供了受保护的可重写 beforeExecute(Thread, Runnable) 和 afterExecute(Runnable, Throwable) 方法,这些方法在每个任务执行之前和之后调用。这些可用于操纵执行环境;例如,重新初始化 ThreadLocals、收集统计信息或添加日志条目。此外,可以重写方法终止()以执行执行器完全终止后需要完成的任何特殊处理。
我们可以使用终止方法来通知我们同样的事情!但我们该如何使用它呢?
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 5; i++) { int temp = i; executorService.submit(() -> { task(temp); }); } executorService.shutdown(); System.out.println("ExecutorService is shutdown"); } private static void task(int temp) { try { TimeUnit.SECONDS.sleep(1L); System.out.println("Task " + temp + " completed"); } catch (InterruptedException e) { throw new RuntimeException(e); } }
如果您不喜欢匿名类(像我一样),您始终可以自己扩展 ThreadPoolExecutor 来创建自定义类。
ExecutorService is shutdown Task 1 completed Task 2 completed Task 0 completed Task 4 completed Task 3 completed
这是验证它是否按照我们的预期工作的输出。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
您还使用了哪些其他相对未知的片段?请在评论中告诉我!
以上是掌握 ExecutorService 关闭:跟踪线程池终止的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

公司安全软件导致部分应用无法正常运行的排查与解决方法许多公司为了保障内部网络安全,会部署安全软件。...

将姓名转换为数字以实现排序的解决方案在许多应用场景中,用户可能需要在群组中进行排序,尤其是在一个用...

在使用MyBatis-Plus或其他ORM框架进行数据库操作时,经常需要根据实体类的属性名构造查询条件。如果每次都手动...

系统对接中的字段映射处理在进行系统对接时,常常会遇到一个棘手的问题:如何将A系统的接口字段有效地映�...

Java对象与数组的转换:深入探讨强制类型转换的风险与正确方法很多Java初学者会遇到将一个对象转换成数组的�...

在使用IntelliJIDEAUltimate版本启动Spring...

电商平台SKU和SPU表设计详解本文将探讨电商平台中SKU和SPU的数据库设计问题,特别是如何处理用户自定义销售属...

Redis缓存方案如何实现产品排行榜列表的需求?在开发过程中,我们常常需要处理排行榜的需求,例如展示一个�...
