五种线程池的对比与使用

今天对五种常见的java内置线程池进行讲解。

线程使用的demo

public static void cache() {ExecutorService pool = Executors.newCachedThreadPool();long start = System.currentTimeMillis();pool.execute(() -> {int sum = 0;for (int i = 0; i < 10; i++) {sum = (int) Math.sqrt(i * i - 1 + i);System.out.println(sum);}});System.out.println("cache: " + (System.currentTimeMillis() - start));}

newCachedThreadPool

  • 重用之前的线程
  • 适合执行许多短期异步任务的程序。
  • 调用 execute() 将重用以前构造的线程
  • 如果没有可用的线程,则创建一个新线程并添加到池中
  • 默认为60s未使用就被终止和移除
  • 长期闲置的池将会不消耗任何资源

源码:

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

通过源码可以看出底层调用的是ThreadPoolExecutor方法,传入一个同步的阻塞队列实现缓存。

下面说一下ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}

通过源码可以看出,我们可以传入线程池的核心线程数(最小线程数),最大线程数量,保持时间,时间单位,阻塞队列这些参数,最大线程数设置为jvm可用的cpu数量为最佳实践

newWorkStealingPool

  • 获取当前可用的线程数量进行创建作为并行级别
  • 使用ForkJoinPool

源码:

public static ExecutorService newWorkStealingPool() {return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);}

通过源码可以看出底层调用的是ForkJoinPool线程池

下面说一下ForkJoinPool

public ForkJoinPool(int parallelism,ForkJoinWorkerThreadFactory factory,UncaughtExceptionHandler handler,boolean asyncMode) {this(checkParallelism(parallelism),checkFactory(factory),handler,asyncMode ? FIFO_QUEUE : LIFO_QUEUE,"ForkJoinPool-" + nextPoolId() + "-worker-");checkPermission();}

使用一个无限队列来保存需要执行的任务,可以传入线程的数量,不传入,则默认使用当前计算机中可用的cpu数量,使用分治法来解决问题,使用fork()和join()来进行调用

newSingleThreadExecutor

  • 在任何情况下都不会有超过一个任务处于活动状态
  • 与newFixedThreadPool(1)不同是不能重新配置加入线程,使用FinalizableDelegatedExecutorService进行包装
  • 能保证执行顺序,先提交的先执行。
  • 当线程执行中出现异常,去创建一个新的线程替换之
    源码:
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}

newFixedThreadPool

  • 创建重用固定数量线程的线程池,不能随时新建线程
  • 当所有线程都处于活动状态时,如果提交了其他任务,
    他们将在队列中等待一个线程可用
  • 线程会一直存在,直到调用shutdown

源码:

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

newScheduledThreadPool

  • 设定延迟时间,定期执行
  • 空闲线程会进行保留

源码:

return new ScheduledThreadPoolExecutor(corePoolSize);

通过源码可以看出底层调用的是一个ScheduledThreadPoolExecutor,然后传入线程数量

下面来介绍一下ScheduledThreadPoolExecutor

public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}

通过源码可以看出底层调用了ThreadPoolExecutor,维护了一个延迟队列,可以传入线程数量,传入延时的时间等参数,下面给出一个demo

public static void main(String[] args) {ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);for (int i = 0; i < 15; i = i + 5) {pool.schedule(() -> System.out.println("我被执行了,当前时间" + new Date()), i, TimeUnit.SECONDS);}pool.shutdown();}

执行结果

我被执行了,当前时间Fri Jan 12 11:20:41 CST 2018
我被执行了,当前时间Fri Jan 12 11:20:46 CST 2018
我被执行了,当前时间Fri Jan 12 11:20:51 CST 2018

有的小伙伴可能会用疑问,为什么使用schedule()而不使用submit()或者execute()呢,下面通过源码来分析

    public void execute(Runnable command) {schedule(command, 0, NANOSECONDS);}public Future<?> submit(Runnable task) {return schedule(task, 0, NANOSECONDS);}

通过源码可以发现这两个方法都是调用的schedule(),而且将延时时间设置为了0,所以想要实现延时操作,需要直接调用schedule()

下面我们再来分析一下submit()和execute()的以及shutdown()和shutdownNow()的区别

  • submit(),提交一个线程任务,可以接受回调函数的返回值吗,适用于需要处理返回着或者异常的业务场景
  • execute(),执行一个任务,没有返回值
  • shutdown(),表示不再接受新任务,但不会强行终止已经提交或者正在执行中的任务
  • shutdownNow(),对于尚未执行的任务全部取消,正在执行的任务全部发出interrupt(),停止执行

五种线程池的适应场景

  1. newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于服务器负载较轻,执行很多短期异步任务。
  2. newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于可以预测线程数量的业务中,或者服务器负载较重,对当前线程数量进行限制。
  3. newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务,并且在任意时间点,不会有多个线程是活动的场景。
  4. newScheduledThreadPool:可以延时启动,定时启动的线程池,适用于需要多个后台线程执行周期任务的场景。
  5. newWorkStealingPool:创建一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用cpu数量的线程来并行执行,适用于大耗时的操作,可以并行来执行

 

转自:https://www.jianshu.com/p/135c89001b61

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

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

相关文章

16进制加法 keil_C/C++编程笔记:C语言进制详解,二进制、八进制和十六进制

我们平时使用的数字都是由 0~9 共十个数字组成的&#xff0c;例如 1、9、10、297、952 等&#xff0c;一个数字最多能表示九&#xff0c;如果要表示十、十一、二十九、一百等&#xff0c;就需要多个数字组合起来。例如表示 58 的结果&#xff0c;一个数字不够&#xff0c;只能”…

MySQL的索引是什么?怎么优化?

索引类似大学图书馆建书目索引&#xff0c;可以提高数据检索的效率&#xff0c;降低数据库的IO成本。MySQL在300万条记录左右性能开始逐渐下降&#xff0c;虽然官方文档说500~800w记录&#xff0c;所以大数据量建立索引是非常有必要的。MySQL提供了Explain&#xff0c;用于显示…

通达信板块监控指标_通达信洞察强势板块指标公式

N:13;P:4;RN:27;VVAR1:(MA(CLOSE,80)-MA(CLOSE,13)/3);VVAR2:( MA((CLOSE-VVAR1)/VVAR1,1));VVAR3:(CLOSE-LLV(LOW,28))/(HHV(HIGH,28)-LLV(LOW,28))*100;VVAR4:SMA(VVAR3,4,1);MMA:EMA(VVAR2,12)*0.7;MMB:EMA(VVAR2,3);快到底:IF(LLV(MMB-MMA,12)>0,0,-20),LINETHICK2,COLO…

12306能删候补订单记录_12306候补购票功能在哪里怎么用 火车票候补购票使用攻略...

12月27日&#xff0c;12306火车票官方推出了一个「候补购票」功能&#xff0c;目前已经开启春运试点&#xff0c;对于购买火车票的用户来说&#xff0c;当没票可买的时候&#xff0c;可以提交候补购票&#xff0c;又多了一种购票途径了。不过&#xff0c;很多小伙伴对于候补购票…

GIT提交message规范

<type>(<scope>): <subject> <body> <footer> # type 用于说明 commit 的类别&#xff0c;只允许使用下面7个标识。 feat: 新功能&#xff08;feature&#xff09; fix: 修补bug docs: 文档&#xff08;documentation&#xff09; style: 格…

git实现审核功能_一文教你如何搭建PDD分佣小程序实现财富自由

随着拼多多的火爆&#xff0c;很多淘客以各种方式通过推广拼多多商品获取返佣来月入万元&#xff0c;实现财富自由。只要你有流量或者足够努力&#xff0c;像其他淘客一样实现睡后过万财富自由不是梦。本文通过详细教程教你快速搭建属于自己的PDD分佣小程序&#xff0c;完成自己…

9型转x型 cobol_兰州一餐馆推鸳鸯牛肉面 9种面型一面多吃

来源标题&#xff1a;兰州一餐馆推鸳鸯牛肉面&#xff0c;清汤酸菜各一边还有9种面型&#xff0c;网友&#xff1a;能连吃三碗近日&#xff0c;位于甘肃兰州的一家牛肉面馆推出了鸳鸯牛肉面。一个大碗分隔为两边&#xff0c;一边是传统清汤牛肉面&#xff0c;另一边是酸菜牛肉面…

gitignore不起作用

.gitignore中已经标明忽略的文件目录下的文件&#xff0c;git push的时候还会出现在push的目录中&#xff0c;原因是因为在git忽略目录中&#xff0c;新建的文件在git中会有缓存&#xff0c;如果某些文件已经被纳入了版本管理中&#xff0c;就算是在.gitignore中已经声明了忽略…

java填空题 在非静态成员方法中_成本加成定价法的优点有

【单选题】以下Math类的方法中,-4.4通过哪个方法运算后,结果为-5.0?【填空题】以下程序的输出结果为?【单选题】下列方法定义中,正确的是()【判断题】Java 中被 final 关键字修饰的变量,不能被重新赋值。【简答题】请按以下要求编写程序 (1) 创建一个Rectangle类,添加width和…

【算法系列之十三】二叉树两叶节点的最大距离

1、题目描述 给定一棵二叉树&#xff0c;计算这课二叉树的直径长度&#xff0c;即为二叉树任意两个节点间的最长路径。比如&#xff1a; 这棵二叉树的最长路径为3。 2、解题思路 使用递归进行求解&#xff0c;每次递归的过程中&#xff0c;先求出以某个节点为树根的二…

date比较大小 mybatis_Hibernate 和 MyBatis 哪个更好用?

Java大联盟帮助万千Java学习者持续成长关注作者&#xff5c;SylvanasSun郑沐兴https://zhuanlan.zhihu.com/p/21966051B 站搜索&#xff1a;楠哥教你学Java获取更多优质视频教程前言由于编程思想与数据库的设计模式不同&#xff0c;生出了一些ORM框架。核心都是将关系型数据库和…

简单的cpu飙升排查方法

1先来一段飙升代码 public class FindJavaThreadInTaskManager {public static void main(String[] args) {Thread thread new Thread(new Worker());thread.start();}static class Worker implements Runnable {Overridepublic void run() {while (true) {System.out.printl…

tortoisesvn创建部署项目_FrameWork如何进行云托管部署

介绍CloudBase Framework 是云开发官方出品的云原生一体化部署工具&#xff0c;可以帮助开发者将静态网站、后端服务和小程序等应用&#xff0c;一键部署到云开发 Serverless 架构的云平台上&#xff0c;自动伸缩且无需关心运维&#xff0c;聚焦应用本身&#xff0c;无需关心底…

【算法系列之十四】最大子序和

1、题目描述 给定一个整数数组 nums &#xff0c;找到一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大&#xff0c;为 6。 2、…

python的代码复用技术_Python__函数和代码复用

主要内容函数的定义和使用实例:七段数码管的绘制代码复用与函数递归PyInstall库的使用实例&#xff1a;科赫雪花小包裹函数的定义与使用函数的理解与定义函数的使用及调用过程函数的参数传递函数的返回值局部变量和全局变量lambda函数------------------------------------函数…

Queue:poll、offer、element、peek的区别

队列是一种特殊的线性表&#xff0c;它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#xff09;进行插入操作。进行插入操作的端称为队尾&#xff0c;进行删除操作的端称为队头。队列中没有元素时&#xff0c;称为空队…

python实现k均值算法_python实现kMeans算法

聚类是一种无监督的学习&#xff0c;将相似的对象放到同一簇中&#xff0c;有点像是全自动分类&#xff0c;簇内的对象越相似&#xff0c;簇间的对象差别越大&#xff0c;则聚类效果越好。1、k均值聚类算法k均值聚类将数据分为k个簇&#xff0c;每个簇通过其质心&#xff0c;即…

mysql给数据量大的表添加索引的办法

有一个问题&#xff0c;一张表有3百万条记录&#xff0c;随着时间的增加&#xff0c;记录量会更多&#xff0c;此时查询速度很慢。在创建此表前没有未相应字段添加索引&#xff0c;所以此时需要为表添加索引。但是因为数据量大的原因&#xff0c;索引添加不成功&#xff0c;想了…

修改背景图片_我花了5小时,为网易修改了一份内容超多的PPT,效果超级赞!!...

微信扫码观看全套Excel、Word、PPT视频作者&#xff1a;宋雪贤 来源&#xff1a;PPT进化论(ID&#xff1a;PPTjinhualun)哈喽&#xff0c;大家好&#xff0c;不知道您看过《我花了3个小时&#xff0c;为京东修改了一份PPT&#xff0c;效果好到惊人&#xff01;》这篇案例修改文…

MySQL千万级别大表如何优化?

当MySQL单表记录数过大时&#xff0c;增删改查性能都会急剧下降&#xff0c;可以参考以下步骤来优化&#xff1a; 单表优化 除非单表数据未来会一直不断上涨&#xff0c;否则不要一开始就考虑拆分&#xff0c;拆分会带来逻辑、部署、运维的各种复杂度&#xff0c;一般以整型值…