Java之ThreadPoolExcutor和四种常见的线程池

一、ThreadPoolExcutors的作用

java提供了ThreadPoolExcutors来创建一个线程池,我们为什么要用线程池呢?
1.降低资源的消耗:通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗

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

3.提高线程的可管理性

 

 

 

 

 

 

二、ThreadPoolExecutor构造函数参数详细介绍

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,即无限大,然后核心线程数corePoolSize一般是0.

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

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

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

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

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

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

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

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

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

线程池遵循的原则:
其会优先创建核心线程,执行任务,当核心线程增加CorePoolSize后,我们会把任务添加到work Queue中,当work Queue里面的任务也塞满了,线程池就会创建非核心线程执行去执行任务,当线程达到maximumPoolSize时候和work queue也达最大值时候我们会执行对应的拒绝策略

 

 

 

三、4类常见的线程池

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));
}

 

 

 

 

四、为什么《阿里巴巴Java开发手册》上要禁止使用Executors来创建线程池

 Executors创建出来的线程池使用的全都是无界队列,而使用无界队列会带来很多弊端,最重要的就是,它可以无限保存任务,因此很有可能造成OOM异常。同时在某些类型的线程池里面,使用无界队列还会导致maxinumPoolSize、keepAliveTime、handler等参数失效 

 

 

 

五、我们用代码测试下


import java.util.*;
import java.lang.*;
import java.io.Serializable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;class Rextester
{  private static int produceTaskSleepTime = 5;private static int consumeTaskSleepTime = 1000;private static int taskMaxNumber = 10; //定义最大添加10个线程到线程池中public static void main(String args[]) {//构造一个线程池//该策略默默的丢弃无法处理的任务,不予任何处理。ThreadPoolExecutor threadPool = getTpe("DiscardPolicy");//该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。//ThreadPoolExecutor threadPool = getTpe("DiscardOldestPolicy");for (int i = 1; i <= taskMaxNumber; i++) {try {//添加任务到线程池,我们要知道添加的任务是RunnableString value = "value is: " + i;System.out.println("put:" + value);threadPool.execute(new ThreadPoolTask(value));//线程休息一段时间,方便我们分析结果Thread. sleep(produceTaskSleepTime);} catch (Exception e) {e.printStackTrace();}}}/*** 线程池执行的任务*/public static class ThreadPoolTask implements Runnable {//保存任务所需要的数据private String value;public ThreadPoolTask(String value) {this.value = value;}public void run() {//打印语句System. out.println("start------" + value);try {Thread. sleep(consumeTaskSleepTime);} catch (Exception e) {e.printStackTrace();}value = "";}}/***初始化线程池 */public static ThreadPoolExecutor getTpe(String type) {if ("DiscardOldestPolicy".equals(type)) {return  new ThreadPoolExecutor(2, 4, 3,TimeUnit. SECONDS, new ArrayBlockingQueue<Runnable>(3),new ThreadPoolExecutor.DiscardOldestPolicy()); } else {return  new ThreadPoolExecutor(2, 4, 3,TimeUnit. SECONDS, new ArrayBlockingQueue<Runnable>(3),new ThreadPoolExecutor.DiscardPolicy()); 	}//DiscardPolicy DiscardOldestPolicy}
}

运行结果:

put:value is: 1
start------value is: 1
put:value is: 2
start------value is: 2
put:value is: 3
put:value is: 4
put:value is: 5
put:value is: 6
start------value is: 6
put:value is: 7
start------value is: 7
put:value is: 8
put:value is: 9
put:value is: 10
start------value is: 3
start------value is: 4
start------value is: 5

我们把上面的生成线程池的代码不//

ThreadPoolExecutor threadPool = getTpe("DiscardOldestPolicy");

运行结果如下

put:value is: 1
start------value is: 1
put:value is: 2
start------value is: 2
put:value is: 3
put:value is: 4
put:value is: 5
put:value is: 6
start------value is: 6
put:value is: 7
start------value is: 7
put:value is: 8
put:value is: 9
put:value is: 10
start------value is: 8
start------value is: 9
start------value is: 10

 

部分内容参考了博客:https://blog.csdn.net/qq_34835058/article/details/80497602



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287832.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索链路追踪在.NET6工业物联网项目中的应用

如果觉得有用&#xff0c;请留言学到了。已经会了的老哥&#xff0c;请留言就这&#xff1f;可能遇到的问题工业物联网系统自上而下一般分为ERP、Mes、SCADA、WCS、边缘网关、设备等一个生产订单从SAP发送到设备要经过上述多个系统&#xff0c;当某个环节出现问题&#xff0c;可…

《零基础看得懂的C语言入门教程 》——(三)轻轻松松理解第一个C语言程序

一、学习目标 了解C语言代码的一般结构了解函数的概念了解printf函数的使用方法了解头文件的概念了解system函数的使用方法 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误…

hdu_1728_逃离迷宫(bfs)

题目连接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1728 题意&#xff1a;走迷宫&#xff0c;找最小的拐角 题解&#xff1a;对BFS有了新的理解&#xff0c;DFS剪枝应该也能过&#xff0c;用BFS就要以拐角作为增量来搜&#xff0c;即以当前点为坐标&#xff0c;4…

把文件放在SD卡

2019独角兽企业重金招聘Python工程师标准>>> 在程序中访问SDCard&#xff0c;你需要申请访问SDCard的权限。 在AndroidManifest.xml中加入访问SDCard的权限如下: <!-- 在SDCard中创建与删除文件权限--> <uses-permissionandroid:name"android.permiss…

python分层聚类集群合并_24、python分层聚类案例(scipy方法)

目录1、分层聚类算法2、方法3、分析步骤4、案例1、分层聚类算法层次聚类算法又称为树聚类算法&#xff0c;它根据数据之间的距离&#xff0c;透过一种层次架构方式&#xff0c;反复将数据进行聚合&#xff0c;创建一个层次以分解给定的数据集。2、方法01 聚类方法linkagescipy.…

【经典回放】多种语言系列数据结构算法:数组

数组如同前面学过的顺序表,一次性申请一片地址连续的存储空间,我们还知道,计算机中数组是以一维的形式存储的,因为计算机的内存的一维的。在知道了多维数据的计算机存储方式后,我们还要知道构造一个多维数据的方法,并构造ADT,具体做法如下所示: 内容和步骤: 1、C语言中…

stl中Priority Queues(优先队列)的基本用法

博客搬家啦 blog.ma6174.comstl中Priority Queues(优先队列)的基本用法 C优先队列类似队列&#xff0c; 但是在这个数据结构中的元素按照一定的断言排列有序。 C Priority Queues(优先队列) empty 语法: bool empty(); empty()函数返回真(true)如果优先队列为空&#xff0c;否则…

如何用 windbg 导出 C# 中的 string 内容?

咨询区 driis我在用 windbg 调试一个生产上的 程序卡死 故障 &#xff0c;在线程栈上有一个 string 类型的参数相当大&#xff0c;我用 !dumpobj 命令不能正常显示内容&#xff0c;参考如下&#xff1a;0:036> !do 00000001b30d8668 Name: System.String MethodTable: 00000…

《零基础看得懂的C语言入门教程 》——(四)C语言的基本数据类型及变量

一、学习目标 了解C语言的基本数据类型了解变量的基本概念了解变量的使用方法了解了变量的命名方法了解格式占位符了解变量的输出 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离…

android一句话搞定图片加载

http://square.github.io/picasso/ Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView); gradle中添加 compile com.squareup.picasso:picasso:2.5.2 转载于:https://www.cnblogs.com/rwxwsblog/p/5467874.html

转HTML+CSS总结/深入理解CSS盒子模型

原文地址&#xff1a;http://www.chinaz.com/design/2010/1229/151993.shtml 前言&#xff1a;前阵子在做一个项目时&#xff0c;在页面布局方面遇到了一点小问题&#xff0c;于是上stackoverflow上求助。ifaou在帮助我解决我问题的同时&#xff0c;还推荐我阅读一篇有关CSS盒子…

主成分分析步骤_多元分析(1)--主成分分析

主成分分析主成分分析&#xff08;PCA&#xff09;是数据降维的一种常见方法&#xff0c;其它常见的方法还有因子分析&#xff08;FA&#xff09;,独立成分分析&#xff0c;在进行大数据处理时&#xff0c;因为数据有很多特征&#xff0c;维数过高&#xff0c;不容易进行处理且…

ArcGIS实验教程——实验十九:网络分析(最短路径实现)

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 一、实验描述 网络分析模块用于实现基于网络数据集的网络分析功能,包括路径分析、服务区分析、最近设施点分析、OD成本矩阵分析、多路径配送分析、位置分配分析和高级网络的管理与创建等。 网络…

设计模式之策略模式和状态模式

1 策略模式 我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法&#xff0c; 我们可以简单理解为更加不同的策略对象&#xff0c;执行不同策略方法。 2 类图 3 代码实现 1&#xff09;接口&#xff1a;Strat…

期待已久的Java 9 今日发布

人们期待已久的Java SE 9.0将在2017年9月21日发布&#xff0c;它会带来一些重要的变化。\\JDK 9的核心变化就是引入了一种新的Java编程组件&#xff0c;也就是模块&#xff0c;按照Oracle的说法&#xff0c;它是一个可命名的、自描述的代码和数据集合。模块技术的核心目标是减少…

AspNetCore7.0源码解读之UseMiddleware

前言本文编写时源码参考github仓库主分支。aspnetcore提供了Use方法供开发者自定义中间件&#xff0c;该方法接收一个委托对象&#xff0c;该委托接收一个RequestDelegate对象&#xff0c;并返回一个RequestDelegate对象&#xff0c;方法定义如下&#xff1a;IApplicationBuild…

边工作边刷题:70天一遍leetcode: day 11-3

Single Number I/II II的python解是网上抄的&#xff0c;其实可以AC&#xff0c;但是python不会像c/java那样自动overflow&#xff0c;而是转化成long。所以如果有负数的情况会得到一个巨大的正数解&#xff0c;比如 Input:[-2,-2,1,1,-3,1,-3,-3,-4,-2] Output:4294967292 Exp…

《零基础看得懂的C语言入门教程 》——(五)C语言的变量、常量及运算

一、学习目标 了解C语言变量的其它创建方式了解C语言常量了解C语言的运算符 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误区 第二篇&#xff1a;&#xff08;二&#xff…

实战使用Axure设计App,使用WebStorm开发(4) – 实现页面UI

系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求 实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目 实战使用Axure设计App,使用WebStorm开发(3) – 构建页面架构 实战使用Axure设计App,使用WebStorm开发(4) – 实现页面UI 实战使用Axu…

ArcGIS实验教程——实验二十:ArcGIS数字高程模型DEM建立

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 一、实验描述 本实验讲述DEM的创建方法和过程。DEM的采集方法有四种:地面测量、摄影测量、空间站、地形图数字化。 二、实验内容 1、插值法DEM建立 2、创建TIN 3、TIN转栅格 4、生成等高线 …