创建线程池的七种方式

2023-11-12

在 Java 语言中,并发编程往往都是通过床架线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景。总结来说线程池的创建可以分为两大类:

通过 Executors 创建

通过 ThreadPoolExecutor 创建

以上这两类创建线程池的方式有 7 种具体实现方法,这 7 种方法便是本文要说的创建线程池的七种方式。分别是:

方法 含义
Executors.newFixedThreadPool() 创建一个大小固定的线程池,可控制并发的线程数,超出的线程会在队列中等待
Executors.newCachedThreadPool() 创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程
Executors.newSingleThreadExecutor() 创建单个线程的线程池,可以保证先进先出的执行顺序
Executors.newScheduledThreadPool() 创建一个可以执行延迟任务的线程池
Executors.newSingleThreadScheduledExecutor() 创建一个单线程的可以执行延迟任务的线程池
Executors.newWorkStealingPool() 创建一个抢占式执行的线程池
ThreadPoolExecutor() 手动创建线程池,可自定义相关参数

Executors.newFixedThreadPool():创建一个固定大小的线程池,可控制并发的线程数。

public class FixedThreadPoolDemo {

    public static void main(String[] args) {

        // 创建 2 个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        // 创建任务
        Runnable runnable = () -> System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
        // 线程池执行任务(一次添加 8 个任务)
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
    }

}

创建一个具有 2 个线程的线程池,执行 8 个任务,执行结果为:

Executors.newCachedThreadPool():创建一个可缓存的线程池,若线程数超过人物所需,那么多余的线程会被缓存一段时间后再回收,若线程数不够,则会新建线程。

public class CachedThreadPoolDemo {

    public static void main(String[] args) {

        // 创建线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // 执行任务
        for (int i = 0; i < 5; i++) {
            threadPool.execute(() -> {
                System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            });
        }
    }

}

创建了一个具有 5 个线程的线程池来执行相应的任务。

使用场景

CachedThreadPool 是根据短时间的任务量来决定创建的线程数量的,所以它适合短时间内有突发大量任务的处理场景。

Executors.newSingleThreadExecutor():创建只有单个线程的线程池,可以保证先进先出的顺序。

public class SingleThreadExecutorDemo {

    public static void main(String[] args) {

        // 创建线程池
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        // 执行任务
        for (int i = 0; i < 10; i++) {
            int index = i;
            threadPool.execute(() -> {
                System.out.println(index + ": 任务被执行: " + Thread.currentThread().getName());
            });
        }
    }

}

如果在打印语句下再加一行睡眠的语句,就会看到每个一段时间输出任务被执行的过程~

try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Executors.newScheduledThreadPool():创建一个可以执行延迟任务的线程池。

public class ScheduledThreadPoolDemo {

    public static void main(String[] args) {
        // 创建线程池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
        // 添加定时执行任务(1s 后执行)
        System.out.println("添加任务,时间:" + new Date());
        threadPool.schedule(() -> {
            System.out.println("任务被执行,时间:" + new Date());
        }, 2, TimeUnit.SECONDS);
    }

}

创建一个延迟 2 秒执行任务的线程池。

Executors.newSingleThreadScheduledExecutor():创建一个单线程的可以执行延迟任务的线程池。这种线程池可以看做是 ScheduledThreadPool 的单线程版本。

public class SingleThreadScheduledExecutorDemo {

    public static void main(String[] args) {
        // 创建线程池
        ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
        // 添加定时执行任务(2s 后执行)
        System.out.println("添加任务,时间:" + new Date());
        threadPool.schedule(() -> {
            System.out.println("任务被执行,时间:" + new Date());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        }, 2, TimeUnit.SECONDS);
    }

}

Executors.newWorkStealingPool():创建一个抢占式执行的线程池,执行任务的顺序不确定。需要注意的是此方法是 JDK 1.8 版本新增的,所以 1.8 版本之前的程序中不能使用。

public class WorkStealingPoolDemo {

    public static void main(String[] args) {
        // 创建线程池
        ExecutorService threadPool = Executors.newWorkStealingPool();
        // 执行任务
        for (int i = 0; i < 10; i++) {
            final int index = i;
            threadPool.execute(() -> {
                System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
            });
        }
        // 确保任务执行完成
        while (!threadPool.isTerminated()) {
        }
    }

}

需注意与 SingleThreadExecutor 单个线程的线程池的比较。

可以看到,任务的执行顺序并不是确定的,因为这是抢占式的线程池,哪个任务抢到,哪个任务先执行。

ThreadPoolExecutor():这是最原始,也是最推荐的手动创建线程池的方法。创建时支持自定义某些属性,比如核心线程数、最大线程数等。

public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {

        // 创建线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
        // 执行任务
        for (int i = 0; i < 10; i++) {
            final int index = i;
            threadPool.execute(() -> {
                System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
            });
        }
    }

}

创建一个具有 10 个核心线程、最大线程数为 10 的线程池。具体可设置的参数请参考:线程池七大参数_文丑颜不良啊的博客-CSDN博客

本文参考自:Java 中线程池的 7 种创建方式! - 掘金

IDEA 背景图可自取:

链接:https://pan.baidu.com/s/1wFNqHIfYKOdwE_d4BKW85A
提取码:1wo0

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建线程池的七种方式 的相关文章

  • Math.random() 解释

    这是一个非常简单的 Java 尽管可能适用于所有编程 问题 Math random 返回 0 到 1 之间的数字 如果我想返回零到百之间的整数 我会这样做 int Math floor Math random 101 在一到一百之间 我会这
  • 在 catch 块中重新抛出异常是否有意义?

    从 catch 块中抛出异常只是为了记录消息以便我们确定导致异常的原因是否有意义 Code public void saveLogs Logs logs throws RemoteException try LogsOps saveLogs
  • 如何使用 Java 以独立于平台的方式读取 Windows 共享驱动器?

    如何使用 Java 从 Windows 共享驱动器中读取数据 以便执行读取的 Java 代码可以在任何平台上同样正确地运行 您可以使用JCIFS http jcifs samba org 使用纯 Java 代码访问 SMB CIFS 共享
  • 如何在 Java 中验证从 Azure AD B2C 生成的 JWT 令牌?

    我正在寻找 Java 代码示例来验证 Azure AD B2C 令牌 我们可以使用哪些依赖项 所有 JWT 令牌的 JWT 令牌验证步骤或代码是否相同还是会有所不同 我们的项目中没有使用 Spring Security 有大量的图书馆her
  • 将倒计时器从 10 秒改为 1 秒

    我有一个倒计时器 它以 1 秒的增量从 10000 毫秒倒计时到 0 毫秒 以使按钮在 10 秒后可单击 尽管计时器是准确的并且按照代码的说明执行操作 但我想更改秒的表示方式 但我不知道如何更改 java void startTimer c
  • JTree 避免重新加载后崩溃

    我正在尝试找到解决崩溃问题的方法JTree重新加载后 情况 JTree Office A Office A 1 Office A 1 1 Office A 1 2 Office B Office B 1 Office B 1 1 Offic
  • 视频文件转换/转码 Google App Engine

    我想启动一个云计算项目 其简单任务是 接收上传的视频文件 对它们进行一些转码 转换 允许用户下载 流式传输生成的文件 我刚在想ffmpeg作为集成在的外部命令行工具Java Google App engine Application 由于很
  • 从 java 类生成 xsd 的实用程序

    我想为以下类生成 xsd public class Node private String value private List
  • java.time.LocalDate 到 java.util.Date

    转换的最佳方式是什么java time LocalDate to java util Date Date from dateToReturn atStartOfDay ZoneId systemDefault toInstant 我一直在尝
  • 声纳要求将这一领域定为最终目标

    我的程序中有以下代码 在与 Maven 集成后 我正在运行 SonarQube 5 对其进行代码质量检查 我面临这个错误 将此 public static processStatus 字段设为最终字段 将此 public static pr
  • 如何在不使用反射的情况下查看对象是否是数组?

    在Java中如何在不使用反射的情况下查看对象是否是数组 如何在不使用反射的情况下迭代所有项目 我使用 Google GWT 所以不允许我使用反射 我很想在不使用反射的情况下实现以下方法 private boolean isArray fin
  • 如何解决声纳中的 dodgy:unchecked/unconfirmedcast 问题?

    我在下面的代码中通过声纳获得异常 我该如何解决这个问题 建议我 Override public boolean validate BaseInfo infoObject boolean isValid true AckTransferPay
  • 为什么这段代码可以在 Java 7 中运行,而不能在 Java 8 中运行?

    我目前使用 IDE Eclipse 版本 Neon 2 Release 4 6 2 和版本 java Version 8 Update 131 在此代码中 IDE 给出错误 类型不匹配 无法从字节转换为整数 Integer i byte 1
  • Java如何区分这些具有相同名称/签名的多个方法?

    今天我在追踪一个错误 我注意到我们的一个班级中有一些奇怪的事情 我删除了尽可能多的代码并发布在这里 class A static int obtainNumber return 42 static int obtainNumber retu
  • 如何将 .txt 文件的最后 5 行读入 java

    我有一个包含多个条目的文本文件 例如 hello there my name is JoeBloggs 我如何按降序阅读最后五个条目 即来自 JoeBloggs 那里 我目前有代码只能读取最后一行 public class TestLast
  • 如何在 iText 7 中创建页面大小不等的文档

    如何在 iText 7 中创建页面大小不等的文档 iText7 可以吗 在iText5中 我使用document setPageSize and document newPage 如果您通过高级 API 添加内容 Document add
  • FocusEvent 没有获取 JFormattedTextField 的最后一个值,我如何获取它?

    我有两个JFormattedTextField我的物体JFrame目的 我想要通过这些值进行基本数学 加法 JFormattedTextField对象 我希望当焦点丢失第一个或第二个文本字段时发生这种情况 但当 focusLost 事件没有
  • 如何为用户的活动设置计时器?

    如果用户在 5 小时内停止工作 我需要执行特定的方法 假设用户已登录 但他在 5 小时内没有向数据库的特定表添加任何记录 任何时候用户将记录添加到指定的表中 该特定用户的计时器都应该重置 否则它将继续运行 如果达到 5 小时 应用程序应显示
  • 每次修改代码时都必须 mvn clean install

    我不是来自 Java 世界 但我必须为我的一个项目深入研究它 我不明白为什么每次修改或更新代码时 都必须 mvn clean install 来调试代码的最新版本 你知道为什么吗 尝试按Ctrl Shift F9 热插拔 有时会有所帮助
  • eclipse.ui.menus 的名称过滤器

    我有一个菜单贡献 通过实现org eclipse ui menus扩展点 我想仅为特定文件扩展名 例如 pld 提供此菜单贡献 但我不知道如何使用 visibleWhen 来做到这一点 有任何想法吗 更新 到目前为止我的扩展点

随机推荐

  • 第六天哈希表

    哈希表 哈希表是根据关键码的值而直接进行访问的数据结构 其实呢 数组就是一张哈希表 其中 关键码就是索引下标 然后通过下标访问数组中的元素 什么时候想到用哈希法 当我们遇到了要快速判断一个元素是否出现集合里的时候 就要考虑哈希法 这 要枚举
  • 平衡球迷宫教程(一)

    平衡球迷宫教程 一 今天分享一个简单的小游戏 平衡球迷宫 这个游戏简单易上手 非常适合刚刚接触unity人员作为基础练习 一 建立一个道路 可以让小球在上面滚动 这里我建立的道路是用3D物体中cube建立的起初用的地板plane 但是后期更
  • ChatGPT专业应用:生成奖项方案

    正文共 925 字 阅读大约需要 4 分钟 人力资源等必备技巧 您将在4分钟后获得以下超能力 生成奖项方案 Beezy评级 A级 经过寻找和一段时间的学习 一部分人能掌握 主要提升效率并增强自身技能 推荐人 Kim 编辑者 Yolanda
  • C#文件读写

    C 的IO类库提供了丰富的IO操作 下面我来总结一下其IO类库提供的一些操作文件系统的方法 一 操作驱动器 C 用DriveInfo来操作驱动器 1 创建对象 a 我们可以通过静态方法DriveInfo GetDrives 来获取所有的Dr
  • 掌握VS2010调试 -- 入门指南

    1 导言 在软件开发周期中 测试和修正缺陷 defect defect与bug的区别 Bug是缺陷的一种表现形式 而一个缺陷是可以引起多种Bug的 的时间远多于写代码的时间 通常 debug是指发现缺陷并改正的过程 修正缺陷紧随debug之
  • vue 拖拽功能样式优化

    拖拽需求完成之后 发现拖拽的过程中很丑 放下的时候光标处也是禁止 虽然说功能不影响 但是用户体验还是不太好 不够专业 所以请做以下优化 1 把需要拖拽的图标加上可拖拽属性 div 需要拖拽的元素 div draggable true 2 在
  • 数据库表关系设计

    数据库表设计 设计原则 考虑问题时 一定要站在一头考虑 常用的关联关系 主外键关联 主外键设计原则 我自己的主键可以充当别人的外键 核心知识 主键不能重复的 外键可以重复 一对一 业务场景 用户 user 表与用户详情表 user info
  • sql如何查看数据库表的关联关系?

    SHOW CREATE TABLE 表名 不管是Navicat还是MySQL Workbench 要查询表的创建sql语句的话 在新建查询中执行以下sql SHOW CREATE Table BinLots 执行之后 Create Tabl
  • 在Jenkins管道中添加Webhook

    你有没有尝试过在Jenkins中添加GitHub webhook 在这篇博客中 我将演示在您的管道中添加webhook的最简单方法 首先 什么是webhook webhook的概念很简单 webhook是一个HTTP回调 当通过HTTP P
  • 【简单题】(2018)第九届蓝桥杯省赛 C/C++ A组(第一题、第二题)

    第一题 题目 标题 分数1 1 1 2 1 4 1 8 1 16 每项是前一项的一半 如果一共有20项 求这个和是多少 结果用分数表示出来 类似 3 2当然 这只是加了前2项而已 分子分母要求互质 注意 需要提交的是已经约分过的分数 中间任
  • Linux最全解压命令(*.tar *tar.gz *.gz *.tar.bz2 *.bz2 *tar.xz *.xz *tar.Z *.Z *.rar *.zip *.7z *.7za)

    压缩解压命令 这里重点介绍tar命令 它是一个打包程序 它可 以调用其它的命令 如 gzip bzip2 除此之外还有 rar zip命令 注 无特殊说明 代表文件夹 代表次一级文件夹 代表文件 一 tar 用法 tar 选项 FILE c
  • JavaScript 实现 -- 快速排序

    文章目录 快速排序 快排原理 代码实现 快排过程 时间复杂度 算法稳定性 快速排序 快速排序算法是在分治算法基础上设计出来的一种排序算法 和其它排序算法相比 快速排序算法具有效率高 耗费资源少 容易实现等优点 快排原理 选择一个基准数 通过
  • http://wp.qq.com/index.html,登录页

    1Tj HOKWyW28 TMmb Xf OJiNeTZg9K yE gt f oxqaOEW9 jFA LtDl6 zX wJXf lC nHKnU2Txt1ISzG1B3mhYAL90 e 9DBh8eGt gt u7b3F r Yl1
  • 如何做一个合格的微软技术工程师

    我是荔园微风 作为一名在IT界整整25年的老兵 今天我们来重新审视一下如何做一个合格的微软技术工程师 我认为要做一个合格的微软技术工程师 首先是要有兴趣从事这个职业 现在很多人是因为软件行业的薪资高才进入的 但我的看法是 工程师是没有办法一
  • chown -R 改不了软链接指向的文件权限?

    关于chown命令的奇怪问题 都知道在linux系统中 chown 命令用来修改文件或目录的属组 而 chown 后加 R 参数 则会修改指定目录即该目录下的所有文件的属组 那么 chown 命令修改一个软连接文件的权限呢 比如 chown
  • Android使用OKHttp访问网络获取Cookie和带Cookie的请求

    登录 取得Cookie public void login String username String userpwd FormBody body new FormBody Builder add email username add p
  • leetcode 028.实现strStr(),即查找重复字符串(KMP算法)

    前言 本题是经典的字符串单模匹配的模型 因此可以使用字符串匹配算法解决 常见的字符串匹配算法包括暴力匹配 Knuth Morris Pratt 算法 Boyer Moore 算法 Sunday 算法等 本文 前言 本题是经典的字符串单模匹配
  • Eigen中的基本函数

    Eigen中的基本函数 Eigen中矩阵的定义 include
  • 微服务和分布式一些概念

    2 1分布式一些基本概念 2 1 1微服务概述 微服务 对应用程序而言 微服务架构风格 就像是把一个单独的应用程序开发为一套小服务 每个小服务运行在自己的进程中 并使用轻量级机制通信 通常是HTTP API 这些服务围绕业务能力来构建 并通
  • 创建线程池的七种方式

    在 Java 语言中 并发编程往往都是通过床架线程池来实现的 而线程池的创建方式也有很多种 每种线程池的创建方式都对应了不同的使用场景 总结来说线程池的创建可以分为两大类 通过 Executors 创建 通过 ThreadPoolExecu