首页 Java java教程 掌握 ExecutorService 关闭:跟踪线程池终止

掌握 ExecutorService 关闭:跟踪线程池终止

Jan 05, 2025 am 01:50 AM

Mastering ExecutorService Shutdown: Tracking ThreadPool Termination

假设您想要执行一些任务。由于通过单个线程执行它可能需要相当长的时间才能获得结果,因此您决定使用可靠的 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() 会使主线程立即退出,但后台线程仍然处理已接受的任务直至完成。有什么方法可以让您收到完成通知吗?

我想到了几个解决方案:

  1. 使用 CountDownLatch 来计算任务 - 但由于您不知道任务的数量,所以使用它是不切实际的。
  2. 使用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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1653
14
CakePHP 教程
1413
52
Laravel 教程
1306
25
PHP教程
1251
29
C# 教程
1224
24
公司安全软件导致应用无法运行?如何排查和解决? 公司安全软件导致应用无法运行?如何排查和解决? Apr 19, 2025 pm 04:51 PM

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

如何将姓名转换为数字以实现排序并保持群组中的一致性? 如何将姓名转换为数字以实现排序并保持群组中的一致性? Apr 19, 2025 pm 11:30 PM

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

如何优雅地获取实体类变量名构建数据库查询条件? 如何优雅地获取实体类变量名构建数据库查询条件? Apr 19, 2025 pm 11:42 PM

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

如何使用MapStruct简化系统对接中的字段映射问题? 如何使用MapStruct简化系统对接中的字段映射问题? Apr 19, 2025 pm 06:21 PM

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

Java对象如何安全地转换为数组? Java对象如何安全地转换为数组? Apr 19, 2025 pm 11:33 PM

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

IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? Apr 19, 2025 pm 11:45 PM

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

电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? 电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? Apr 19, 2025 pm 11:27 PM

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

如何利用Redis缓存方案高效实现产品排行榜列表的需求? 如何利用Redis缓存方案高效实现产品排行榜列表的需求? Apr 19, 2025 pm 11:36 PM

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

See all articles