线程池的使用与分析(ThreadPoolExcutors)

2023-11-01

开发中为什么使用线程池

1.降低资源的消耗:通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗

2.提高响应速度:因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行

3.提高线程的可管理性:线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

线程池ThreadPoolExcutors

java提供了ThreadPoolExcutors来创建一个线程池,完整的构造函数如下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

1.int corePoolSize(核心线程数):线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程;核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态);如果设置了 allowCoreThreadTimeOut 为 true,那么核心线程如果不干活(闲置状态)的话,超过一定时间(时长下面参数决定),就会被销毁掉。

2.int maximumPoolSize(线程池能容纳的最大线程数量):线程总数 = 核心线程数 + 非核心线程数。

3.long keepAliveTime(非核心线程空闲存活时长):非核心线程空闲时长超过该时长将会被回收,主要应用在缓存线程池中,当设置了 allowCoreThreadTimeOut 为 true 时,对核心线程同样起作用。

4.TimeUnit unit 空闲线程的存活时间(keepAliveTime 的单位)它是一个枚举类型,常用的如:TimeUnit.SECONDS(秒)、TimeUnit.MILLISECONDS(毫秒)。

5.BlockingQueue workQueue(任务队列):当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务

     常用的workQueue类型:

    (1)SynchornousQueue:这队列接收到任务时会直接交给线程处理,而不保留它,如果所有的线程都在工作,那就创建一   个新的线程来处理这个任务,为了保证不出现线程数达到maxnumPoolSize而不能新建线程的错误,所以使用这个类型 的队列时,maxnumPoolSize一般指定成Integer.MAX_VALUE,即无限大

    (2)LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了 maximumPoolSize 的设定失效,因为总线程数永远不会超过 corePoolSize。

    (3)ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到 corePoolSize 的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了 maximumPoolSize,并且队列也满了,则发生错误。

    (4)DelayQueue:队列内元素必须实现 Delayed 接口,这就意味着你传进去的任务必须先实现 Delayed 接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务。

6.ThreadFactory threadFactory(线程工厂):用来创建线程池中的线程,通常用默认的即可

7.RejectedExecutionHandler handler(拒绝策略):在线程池已经关闭的情况下和任务太多导致最大线程数和任务队列已经饱和,无法再接收新的任务,在上面两种情况下,只要满足其中一种时,在使用 execute() 来提交新的任务时将会拒绝,线程池提供了以下 4 种策略:

  1. AbortPolicy:默认策略,在拒绝任务时,会抛出RejectedExecutionException。

  2. CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。

  3. DiscardOldestPolicy:该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。

  4. DiscardPolicy:该策略默默的丢弃无法处理的任务,不予任何处理。

四类常见的线程池

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

其实他们都是通过ThreadPoolExcutors创建的

1.CachedThreadPool

由Executors的newCachedThreadPool方法创建,不存在核心线程,只存在数量不定的非核心线程,而且其数量最大值为Integer.MAX_VALUE。当线程池中的线程都处于活动时(全满),线程池会创建新的线程来处理新的任务,否则就会利用新的线程来处理新的任务,线程池中的空闲线程都有超时机制,默认超时时长为60s,超过60s的空闲线程就会被回收。和FixedThreadPool不同的是,CachedThreadPool的任务队列其实相当于一个空的集合,这将导致任何任务都会被执行,因为在这种场景下SynchronousQueue是不能插入任务的,SynchronousQueue是一个特殊的队列,在很多情况下可以理解为一个无法储存元素的队列。从CachedThreadPool的特性看,这类线程比较适合执行大量耗时较小的任务。当整个线程池都处于闲置状态时,线程池中的线程都会因为超时而被停止回收,几乎是不占任何系统资源。实现方式如下:

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}
2.FixedThreadPool

由Executors的newFixedThreadPool方法创建。它是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来。FixedThreadPool只有核心线程,且该核心线程都不会被回收,这意味着它可以更快地响应外界的请求。jdk实现如下:FixedThreadPool没有额外线程,只存在核心线程,而且核心线程没有超时机制,而且任务队列没有长度的限制。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}
3.ScheduledThreadPool

通过Executors的newScheduledThreadPool方式创建,核心线程数量是固定的,而非核心线程是没有限制的,并且当非核心线程闲置时它会被立即回收,ScheduledThreadPool这类线程池主要用于执行定时任务和具有固定时期的重复任务,实现方法如下:

public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
 
public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue(), threadFactory);
}
4.SingleThreadPool

通过Executors的newSingleThreadExecutor方法来创建。这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有外界任务一个线程中,这使得这些任务之间不需要处理线程同步的问题,实现方式如下:

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}
参数表
线程池名称 corePoolSize maxnumPoolSize keepAliveTime unit workQueue threadFactory handle 使用场景
CachedThreadPool         0
Integer.MAX_VALUE
60 SECONDS SynchronousQueue defaultThreadFactory defaultHandler 处理执行时间比较短的任务
FixedThreadPool    nThread 0 0 MILLISECONDS LinkedBlockingQueue defaultThreadFactory defaultHandler 已知并发压力的情况下,对线程数做限制
ScheduleThreadPool corePoolSize Integer.MAX_VALUE 10 MILLISECONDS DelayedWorkQueue defaultThreadFactory defaultHandler 需要多个后台线程执行周期任务的场景


SingleThreadPool 1 1 0 MILLISECONDS LinkedBlockingQueue defaultThreadFactory defaultHandler
需要保证顺序执行的场景,并且只有一个线程在执行




                 

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

线程池的使用与分析(ThreadPoolExcutors) 的相关文章

  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 加密 JBoss 配置中的敏感信息

    JBoss 中的标准数据源配置要求数据库用户的用户名和密码位于 xxx ds xml 文件中 如果我将数据源定义为 c3p0 mbean 我会遇到同样的问题 是否有标准方法来加密用户和密码 保存密钥的好地方是什么 这当然也与 tomcat
  • 在 Mac 上正确运行基于 SWT 的跨平台 jar

    我一直致力于一个基于 SWT 的项目 该项目旨在部署为 Java Web Start 从而可以在多个平台上使用 到目前为止 我已经成功解决了由于 SWT 依赖的系统特定库而出现的导出问题 请参阅相关thread https stackove
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • 如何从终端运行处理应用程序

    我目前正在使用加工 http processing org对于一个小项目 但是我不喜欢它附带的文本编辑器 我使用 vim 编写所有代码 我找到了 pde 文件的位置 并且我一直在从 vim 中编辑它们 然后重新打开它们并运行它们 重新加载脚
  • 在mockito中使用when进行模拟ContextLoader.getCurrentWebApplicationContext()调用。我该怎么做?

    我试图在使用 mockito 时模拟 ContextLoader getCurrentWebApplicationContext 调用 但它无法模拟 here is my source code Mock org springframewo
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分

随机推荐

  • 算法:dfs(深度优先搜索算法)

    dfs 暴搜 一条路走到黑 然后回溯 开启另一条路 再一条路走到黑 那么如何对暴搜进行优化 剪枝 当发现某一条树枝时不可能找到答案时 就没必要还在这条路走到黑一直搜索了 将这条树枝减去 趁早换一条路 如图 可以用递归来一条路走到黑 递归最恰
  • JeecgBoot获取当前登录用户信息

    前言 如果使用JeecgBoot项目进行开发的时候 有的场景需要获取当前登录人信息做一些逻辑操作 下面分享下通过前后端分别获取用户的方式 前端获取 本质是使用vuex进行获取 引入store import store from store
  • Java数字反转

    这道题非常像之前做过的一道题 求水仙花数 输出对应位的数字 这题不一样的在于带有小数点 但是除余没法留小数点上的数字 需要变整后除余 求末位数 求末位数 随后倒数第二位直接初余便可以得到 不要忘记和第一个数中间放一个小数点 由于题母给的是f
  • 分割问题中“类间竞争”是怎么回事

    softmax会返回多种不同类别 而sigmoid会得到二值结果 softmax的值域是 0 1 sigmoid的值域是 0 1 sigmoid可以看成是softmax的两类分类的特例
  • 2023华为OD机试真题-分苹果(JAVA、Python、C++)

    题目描述 A B两团体把苹果分为两堆 A盼望依照它的盘算规矩平分苹果 他的盘算规矩是依照二进制加法盘算 而且不盘算走位 12 5 9 1100 0101 9 B的盘算规矩是十进制加法 包含畸形进位 B盼望在满意A的情形下获取苹果分量最多 输
  • xss挑战之旅11关到13关,操作步骤配截图。

    level11 分析代码 相比上一关 多了一个str11 SERVER HTTP REFERER 验证的是http头部的xss注入 使用burp抓包 修改相应的字段 构造http头部referer的payload 头部本身没有Referer
  • 数据的中心化,标准化及意义

    在机器学习回归问题 以及训练神经网络过程中 通常需要对原始数据进行中心化 零均值化 与标准化 归一化 预处理 目的 通过中心化和标准化处理 最终得到均值为0 标准差为1的服从标准正态分布的数据 在多指标评价体系中 由于各评价指标的性质不同
  • OPENSSL ENGINE机制

    OPENSSL ENGINE机制 1 概念 OpenSSL项目是一个开放源代码安全项目 它的目标是开发一个健壮的 商业级的 完整的开放源代码的工具包 用强大的加密算法来实现安全的Socket层 Secure Sockets Layer SS
  • 弱口令招新赛靶机赛道WriteUp

    nmap sS p 22 oG 172 27 13 0 24 grep open 使用该命令扫描网段下开放22端口的主机 发现主机后 信息收集 得到两个开放的端口 22端口 服务为ssh服务 版本为7 6p1 服务器为ubuntu 此版本存
  • Vue3项目搭建教程(create-vue)

    什么是create vue create vue是一个脚手架工具 用来快速创建v3的项目 Vuecli用来创建v2的项目 介绍 Vue CLI create vue是Vue官方新的脚手架工具 底层切换到了 vite 下一代前端工具链 为开发
  • 2021全国省市区街道(乡镇)数据及编码(不包含港澳台)

    已按拼音首字母排序 共31省直辖市 342个城市 3352个区县 41206个街道 乡镇 安徽省 340000 安庆市 340800 安徽安庆经济开发区 340871 菱北街道 340871001 老峰镇 340871100 大观区 340
  • 嵌入式Linux应用开发完全手册(一)嵌入式Linux基础知识

    嵌入式Linux应用开发完全手册 3 嵌入式Linux基础知识 3 1 交叉编译工具 编译工具链 编译工作由几个步骤完成 分别用到了不同的工具 PC端应用 gcc ld objcopy objdump 交叉编译 编译和运行在不同的环境下 a
  • mysql 5.6 创建索引导致表锁阻塞查询

    今天遇到一个表锁 对表进行select操作阻塞 最后发现在表操作时的时候执行了创建索引 导致整个表锁了 测试如下 1 先执行一个慢查询 mysql gt select sleep 500 from order log 2 对表进行创建索引操
  • 链式栈和队列以及重载,const,void(*)补充

    一 C 版链式栈和队列 1 1栈 include
  • 聊一聊TypeScript中的泛型与断言~

    思考 后端接口给前端返回数据时 一般会遵循一定的规律 例如 都有code msg data三个属性 而不同的接口返回的具体数据保存在data中 它的格式是不同的 随便定义一个数据 请求得到用户信息 const res1 code 200 m
  • Openwrt编写GPIO驱动控制LED

    一 驱动的编写 1 创建gpio control driver文件夹 2 在gpio control driver文件夹下再创建src文件夹以及Makefile文件 Makefile文件如下 include TOPDIR rules mk
  • ma5822是什么设备_ma5822是什么设备_华为MA5821-24 - AC远端光接入ONU光纤设备24口 全新原装...

    接口配置 8 FE提供SFP类型上行光接口 支持10G EPON EPON上行方式 16 FE MA582216 FE 16 POTS 面板丝印 交流电源接口 用于连接 接地点 用于设备接地 1个10G GPON GPON或者 维护串口CO
  • 时间序列分析状态空间模型粒子滤波器

    时间序列分析是研究时间序列数据的统计方法 而状态空间模型是一种描述时间序列的框架 粒子滤波器是一种用于状态空间模型的推断方法 下面我将详细解释时间序列分析 状态空间模型和粒子滤波器的概念以及它们之间的关系 时间序列分析是一种研究时间上观测数
  • 瞧瞧别人家的API接口,那叫一个优雅

    前言 在实际工作中 我们需要经常跟第三方平台打交道 可能会对接第三方平台API接口 或者提供API接口给第三方平台调用 那么问题来了 如果设计一个优雅的API接口 能够满足 安全性 可重复调用 稳定性 好定位问题等多方面需求 今天跟大家一起
  • 线程池的使用与分析(ThreadPoolExcutors)

    开发中为什么使用线程池 1 降低资源的消耗 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗 2 提高响应速度 因为线程池中的线程数没有超过线程池的最大上限时 有的线程处于等待分配任务的状态 当任务来时无需创建新的线程就能执行 3