返回顶部
首页 > 资讯 > 精选 >怎么理解ThreadPoolExecutor线程池技术
  • 618
分享到

怎么理解ThreadPoolExecutor线程池技术

2023-06-19 10:06:37 618人浏览 独家记忆
摘要

本篇文章为大家展示了怎么理解ThreadPoolExecutor线程池技术,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是一门多线程的语言,基本上生产环境的Java项目都离不开多线程。而线程

本篇文章为大家展示了怎么理解ThreadPoolExecutor线程池技术,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

Java是一门多线程的语言,基本上生产环境的Java项目都离不开多线程。而线程则是其中最重要的系统资源之一,如果这个资源利用得不好,很容易导致程序低效率,甚至是出问题。

有以下场景,有个电话拨打系统,有一堆需要拨打的任务要执行,首先肯定是考虑多线程异步去执行。假如我每执行一个拨打任务都new一个Thread去执行,当同时有1万个任务需要执行的时候,那么就会新建1万个线程,加上线程各种初始销毁等操作,这个消耗是巨大的。而其实往往实现这些功能的时候,并不是完全需要实时马上完成,只是希望在可控范围内尽量提高执行的并发性能。

因此线程池技术应用而生,Java中最常用的线程池技术就是ThreadPoolExecutor。接下来就整体看看ThreadPoolExecutor的实现。 这个类的注解非常多,很多也是重点,所以就不从注解开始看起。先从使用说起,有个概念先。

基本使用

        // 核心线程        int corePoolSize = 5;        // 最大线程        int maximumPoolSize = 10;        // 线程空闲回收时间        int keepAliveTime = 30;        // 线程空闲回调时间单位        TimeUnit unit = TimeUnit.SECONDS;        // 队列大小        int queueSize = 20;        // 队列        BlockingQueue workQueue = new ArrayBlockingQueue<Runnable>(queueSize);        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);        executor.execute(() -> {            // do something 1        });        executor.execute(() -> {            // do something 2        });

定义好一些必要的参数,构建一个ThreadPoolExecutor对象。然后调用对象的execute()方法即可。 参数说明:

  • corePoolSize,线程池保留的最小线程数。如果线程池中的线程少于此数目,则在执行execut()时创建。

  • maximumPoolSize,线程池中允许拥有的最大线程数。

  • keepAliveTime、unit,当线程闲置时,保持线程存活的时间。

  • workQueue,工作队列,存放提交的等待任务,其中有队列大小的限制。

线程管理机制

非常多人误解了corePoolSize、maximumPoolSize、workQueue的相互关系。不少人认为无论队列选择什么,corePoolSize和maximumPoolSize一定是有用,定义一定是生效的,其实并不然啊!

看下线程基本规则注解说明

怎么理解ThreadPoolExecutor线程池技术

  1. 默认情况下,线程池在初始的时候,线程数为0。当接收到一个任务时,如果线程池中存活的线程数小于corePoolSize核心线程,则新建一个线程。

  2. 如果所有运行的核心线程都都在忙,超出核心线程处理的任务,执行器更多地选择把任务放进队列,而不是新建一个线程。

  3. 如果一个任务提交不了到队列,在不超出最大线程数量情况下,会新建线程。超出了就会报错。

另外,如果想在线程初始化时候就有核心线程,可以调用prestartCoreThread()或prestartAllCoreThread(),前者是初始一个,后者是初始全部。

再看看排队策略

怎么理解ThreadPoolExecutor线程池技术

  • 直接提交,用SynchronousQueue。特点是不保存,直接提交给线程,如果没没线程,则新建一个。

  • 无限提交,用类似LinkedBlockingQueue无界队列。特点是保存所以核心线程处理不了的任务,队列无上限,最大线程也没用。

  • 有限提交,用类似ArrayBlockingQueue有界队列。特点是可以保存超过核心线程的任务,并且队列也是有上限的。超过上限,新建线程(满了抛错)。更好地保护资源,防止崩溃,也是最常用的排队策略。

从以上规则可以看出来,核心线程数和最大线程数,还有队列结构是相互影响的,如何排队,队列多大,最大线程是多少都是不一定的。

再看看保持存活机制

怎么理解ThreadPoolExecutor线程池技术

当超过核心线程数的线程,线程池会让该线程保持存活keepAliveTime时间,超过该时间则会销毁该线程。 另外默认对非核心线程有效,若想核心线程也适用于这个机制,可以调用allowCoreThreadTimeOut()方法。这样的话就没有核心线程这一说了。

综合以上,线程池在多次执行任务后,会一直维持部分线程存活,即使它是闲置的。这样的目的是为了减少线程销毁创建的开销,下次有个任务需要执行,直接从池子里拿线程就能用了。但核心线程不能维护太多,因为也需要一定开销。最大的线程数保护了整个系统的稳定性,避免并发量大的时候,把线程挤满。工作队列则是保证了任务顺序和暂存,系统的可靠性。线程存活规则的目的和维护核心线程的目的类似,但降低了它的存活的时间。

另外还有拒绝机制,它提供了一些异常情况下的解决方案。

怎么理解ThreadPoolExecutor线程池技术

ctl线程状态控制

这个ctl变量是整个线程池的核心控制状态。

怎么理解ThreadPoolExecutor线程池技术

这个ctl代表了两个变量

  • workerCount,生效的线程数。基本可以理解为存活的线程,但某个时候有暂时性的差异。

  • runState,线程池的运行状态。 其中,ctl(int32位)的低29位代表workerCount,所以最大线程数为(2^29)-1。另外3位表示runState。

runState有以下几种状态:

怎么理解ThreadPoolExecutor线程池技术

  • RUNNING:接收新任务,处理队列任务。

  • SHUTDOWN:不接收新任务,但处理队列任务。

  • STOP:不接收新任务,也不处理队列任务,并且中断所有处理中的任务。

  • TIDYING:所有任务都被终结,有效线程为0。会触发terminated()方法。

  • TERMINATED:当terminated()方法执行结束。

当调用了shutdown(),状态会从RUNNING变成SHUTDOWN,不再接收新任务,此时会处理完队列里面的任务。 如果调用的是shutdownNow(),状态会直接变成STOP。 当线程或者队列都是空的时候,状态就会变成TIDYING。 当terminated()执行完的时候,就会变成TERMINATED。

execute()

带着对上面的规则与机制的认识,现在从就这这个入口开始看看源码,到底整个流程是怎么实现的。

怎么理解ThreadPoolExecutor线程池技术

  1. 如果少于核心线程在跑,用这个任务尝试创建一个新线程。

  2. 如果一个任务成功入队,再次检查下线程池状态看是否需要入队,因为可能在入队过程中,状态发送了变化。如果确认入队且没有存活线程,则新建一个空线程。

  3. 如果进不了队,则尝试新建一个线程,如果都失败了。拒绝这个task

对于第二点最后为什么新建一个线程?很容易猜想到,会有一个轮询的机制让下个task出队,直接利用这个空闲线程。

注释基本解释了所有代码,代码也没什么特别的。其中最主要的还是addWoker()这个方法,下面来看看。

addWoker()

先了解下这个方法的整体思路

怎么理解ThreadPoolExecutor线程池技术

从描述可知,addwoker失败,会在线程池状态不对、线程满了或者线程工厂创建线程池失败时候发生。 这个方法比较长,分两段看。先看第一段。

怎么理解ThreadPoolExecutor线程池技术

retry:这种写法,如果比较少看源码的,应该是前所未见的了。这是个循环的位置标记,是java的语法之一。看回代码,这里面for循环还嵌套里一个for循环,而retry:是标记第一个for循环的,后面breakcontinue语句都指向到了retry。说明breakcontinue是都是操作外层的for循环。retry可以是任何变量命名合法的字符。

然后看看外出for循环的if语句

怎么理解ThreadPoolExecutor线程池技术

这个if判断想要执行到return false;,队列为空是一个必要条件。因为addWork()不单只接收新任务会调用到,处理队列中的任务也会调用到。而前面提到SHUTDOWN状态下还会处理队列中的任务的,所以队列不为空是会让它继续执行下去的。

对于内层的for循环

怎么理解ThreadPoolExecutor线程池技术

会先判断worker的数据是否符合corePoolSize和maximumPoolSize的定义,不满足则返回失败。 然后尝试CAS让workerCount自增,如果CAS失败还是继续自旋去自增,直到成功。除非线程池状态发生了变化,发退回到外层for循环重新执行,判断线程池的状态。

第一段的代码,就是让workerCount在符合条件下自增

第二段代码

怎么理解ThreadPoolExecutor线程池技术

这段比较好理解,先创建一个Worker对象,这个Worker里面包含一个由线程工厂创建的线程,和一个需要执行的任务(可以为空)。如果线程创建成功了,那么就加一个重入去把这个新建的Worker对象放到workers成员变量中,在加入之前需要重新判断下线程池的状态和新建线程的状态。如果worker添加到workers成员变量中,就启动这个新建的线程。最后如果添加失败,则执行addWorkFailed(w)

怎么理解ThreadPoolExecutor线程池技术

如果失败了,加锁操作回滚下wokers、workerCount,然后判断下状态看看是否需要终结线程池。

addWorker()大概的流程就这样。

对于其他方法,没有什么特别的,在此不再过多的叙述,有兴趣的可以翻翻源码阅读下。 回顾总结下上面的核心要点

  1. 当核心线程满且忙碌时,线程池倾向于把提交的任务放进队列,而不是新建线程。

  2. 根据选择队列的不同,maximumPoolSize不一定有用的。具体有三种不同的策略。

  3. ctl是线程池的核心控制状态,包含的runState线程池运行状态和workCount有效线程数。

  4. retry:是一种标记循环的语法,retry可以是任何变量命名合法字符。

上述内容就是怎么理解ThreadPoolExecutor线程池技术,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网精选频道。

--结束END--

本文标题: 怎么理解ThreadPoolExecutor线程池技术

本文链接: https://lsjlt.com/news/295316.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 怎么理解ThreadPoolExecutor线程池技术
    本篇文章为大家展示了怎么理解ThreadPoolExecutor线程池技术,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是一门多线程的语言,基本上生产环境的Java项目都离不开多线程。而线程...
    99+
    2023-06-19
  • Java线程池 ThreadPoolExecutor 详解
    目录一 为什么要使用线程池二 线程池原理详解2.1 线程池核心组成2.2 Execute 原理三 线程池的使用3.1 创建线程池3.1.1 自定义线程池3.1.2 功能线程池3.1....
    99+
    2024-04-02
  • 线程池是什么?线程池(ThreadPoolExecutor)使用详解
    点一点,了解更多https://www.csdn.net/ 本篇文章将详细讲解什么是线程池,线程池的参数介绍,线程池的工作流程,使用Executors创建常见的线程池~~~ 目录 点一点,了解更多 文章目录 一、线程池的概念 1.1线...
    99+
    2023-09-03
    java 数据结构 jvm 面试 java-ee
  • java线程池ThreadPoolExecutor类怎么用
    这篇文章将为大家详细讲解有关java线程池ThreadPoolExecutor类怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许...
    99+
    2023-06-29
  • Java线程池ThreadPoolExecutor怎么创建
    本篇内容介绍了“Java线程池ThreadPoolExecutor怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!简介ThreadPo...
    99+
    2023-07-02
  • Python之ThreadPoolExecutor线程池问题怎么解决
    本文小编为大家详细介绍“Python之ThreadPoolExecutor线程池问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python之ThreadPoolExecutor线程池问题怎么解决”文章能帮助大家解决疑惑,下面跟...
    99+
    2023-07-05
  • Java线程池ThreadPoolExecutor源码解析
    目录引导语1、整体架构图1.1、类结构1.2、类注释1.3、ThreadPoolExecutor 重要属性2、线程池的任务提交3、线程执行完任务之后都在干啥 4、总结引导语...
    99+
    2024-04-02
  • python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用
    这篇文章主要介绍了python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中ThreadPoolE...
    99+
    2023-07-02
  • ThreadPoolExecutor线程池原理及其execute方法(详解)
    jdk1.7.0_79 对于线程池大部分人可能会用,也知道为什么用。无非就是任务需要异步执行,再者就是线程需要统一管理起来。对于从线程池中获取线程,大部分人可能只知道,我现在需要一个线程来执行一个任务,那我就把任务丢到线程池里,线程池里有空...
    99+
    2023-05-31
    线程池 execute lex
  • 详解Java并发包中线程池ThreadPoolExecutor
    目录一、线程池简介二、ThreadPoolExecutor类2.1、ThreadPoolExecutor成员变量以含义2.2、ThreadPoolExecutor的参数以及实现原理2...
    99+
    2024-04-02
  • python3线程池ThreadPoolExecutor处理csv文件数据
    目录背景知识点拓展库流程实现代码解释背景 由于不同乙方对服务商业务接口字段理解不一致,导致线上上千万数据量数据存在问题,为了修复数据,通过 Python 脚本进行修改 知识点 Pyt...
    99+
    2024-04-02
  • 怎么使用python3线程池ThreadPoolExecutor处理csv文件数据
    这篇文章主要介绍“怎么使用python3线程池ThreadPoolExecutor处理csv文件数据”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用python3线程池ThreadPoolEx...
    99+
    2023-07-02
  • Java多线程与线程池技术分享
    目录一、序言1、普通执行2、线程池执行二、线程池基础1、核心参数2、参数与池的关系1、通用对比2、拓展对比3、无返回值任务4、有返回值任务三、Executors1、创建单一线程的线程...
    99+
    2024-04-02
  • 怎么在Java并发包中使用ThreadPoolExecutor线程池
    这篇文章给大家介绍怎么在Java并发包中使用ThreadPoolExecutor线程池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、线程池简介线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供...
    99+
    2023-06-15
  • java高并发ThreadPoolExecutor类解析线程池执行流程
    目录摘要核心逻辑概述execute(Runnable)方法addWorker(Runnable, boolean)方法addWorkerFailed(Worker)方法拒绝策略摘要 ...
    99+
    2024-04-02
  • 怎么在java中使用ThreadPoolExecutor创建一个线程池
    这篇文章给大家介绍怎么在java中使用ThreadPoolExecutor创建一个线程池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发...
    99+
    2023-06-14
  • 怎么深入理解线程池
    本篇内容主要讲解“怎么深入理解线程池”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么深入理解线程池”吧!本文将会从以下几个方面来介绍线程池的原理。 为什么要用线程池 线程池...
    99+
    2023-06-15
  • 从java源码分析线程池(池化技术)的实现原理
    目录线程池的起源线程池的定义和使用方案一:Executors(仅做了解,推荐使用方案二)方案二:ThreadPoolExecutor线程池的实现原理前言: 线程池是一个非常重要的知识...
    99+
    2024-04-02
  • Java创建线程池为什么一定要用ThreadPoolExecutor
    目录先说结论OOM风险演示内存溢出原因分析使用ThreadPoolExecutor来改进其他创建线程池的问题总结前言: 在 Java 语言中,并发编程都是依靠线程池完成的,而线程池的...
    99+
    2024-04-02
  • Java线程池的优点及池化技术的应用
    目录1.池化技术2.池化技术应用2.1 线程池2.2 内存池2.3 数据库连接池2.4 HttpClient连接池3.线程池介绍4.线程池优点分析优点1:复用线程,降低资源消耗优点2...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作