线程池ThreadPoolExecutor与ForkJoinPool
一、ThreadPoolExecutor
构造器中各个参数的含义:
- corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
- maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
- keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0
在ThreadPoolExecutor类中有几个非常重要的方法:
- execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。
- submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果(Future相关内容将在下一篇讲述)。
- shutdown()和shutdownNow()是用来关闭线程池的。
- 比如:getQueue() 、getPoolSize() 、getActiveCount()、getCompletedTaskCount()等获取与线程池相关属性的方法
ThreadPoolExecutor简单示例
package constant;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class ThreadTest {public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 200, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());long s1 = System.currentTimeMillis();// 计数控制final CountDownLatch latch = new CountDownLatch(330);for(int i=0;i<330;i++){// 自定义执行体MyTask myTask = new MyTask(i,latch);executor.execute(myTask);System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());}// 控制所有线程全部跑完(异步执行可以去掉)latch.await();long s2 = System.currentTimeMillis();long s =s2-s1;System.out.println("线程池执行时间:"+s); System.out.println("执行完毕=============================");executor.shutdown();}
}class MyTask implements Runnable {private int taskNum;private CountDownLatch latch;public MyTask(int num,CountDownLatch latch) {this.taskNum = num;this.latch = latch;}@Overridepublic void run() {System.out.println("正在执行task "+taskNum);try {Thread.currentThread().sleep(10);} catch (InterruptedException e) {e.printStackTrace();}finally {latch.countDown();}System.out.println("task "+taskNum+"执行完毕");}
}
二、ForkJoinPool
Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork/Join框架要完成两件事情:
1.任务分割:首先Fork/Join框架需要把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割
2.执行任务并合并结果:分割的子任务分别放到双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,启动一个线程从队列里取数据,然后合并这些数据。
在Java的Fork/Join框架中,使用两个类完成上述操作
1.ForkJoinTask:我们要使用Fork/Join框架,首先需要创建一个ForkJoin任务。该类提供了在任务中执行fork和join的机制。通常情况下我们不需要直接集成ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了两个子类:
a.RecursiveAction:用于没有返回结果的任务
b.RecursiveTask:用于有返回结果的任务
2.ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行
任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务(工作窃取算法)。
Fork/Join框架的实现原理
ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责将存放程序提交给ForkJoinPool,而ForkJoinWorkerThread负责执行这些任务。
ForkJoinPool简单示例
package constant;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;public class ForkJoinTask extends RecursiveTask<List<String>> {/*** * @author: FangRen* @version V2.0* @date: 2018年7月2日 下午4:55:15*/private static final long serialVersionUID = 1L;private int THRESHOLD = 2;private int start;private int end;public ForkJoinTask(int start, int end) {this.start = start;this.end = end;}@Overrideprotected List<String> compute() {List<String> list = new ArrayList<>();//如果任务足够小就计算任务boolean canCompute = (end - start) <= THRESHOLD;if (canCompute) {for (int i = start; i < end; i++) {try {Thread.currentThread().sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程池中线程数目:"+ForkJoinTask.getPool().getPoolSize()+",队列中等待执行的任务数目:"+ForkJoinTask.getPool().getQueuedTaskCount());list.add("wo");}return list;}int middle = (end + start) / 2;ForkJoinTask task1 = new ForkJoinTask(start, middle);ForkJoinTask task2 = new ForkJoinTask(middle, end);invokeAll(task1, task2);//等待任务执行结束合并其结果List<String> leftResult = task1.join();List<String> rightResult = task2.join();list.addAll(rightResult);list.addAll(leftResult);return list;}public static void main(String[] args) throws InterruptedException, ExecutionException {List<String> list = new ArrayList<String>();for(int i=1;i<=330;i++){list.add("i------"+i);}System.out.println(list.size());long s1 = System.currentTimeMillis();// 参数默认是cpu数(可以自定义)ForkJoinPool pool = new ForkJoinPool();// 提交可分解的PrintTask任务Future<List<String>> ss = pool.submit(new ForkJoinTask(0,list.size()));//线程阻塞,等待所有任务完成pool.awaitTermination(1, TimeUnit.SECONDS);// 关闭线程池pool.shutdown();long s2 = System.currentTimeMillis();long s =s2-s1;System.out.println(s);}
}
线程池ThreadPoolExecutor与ForkJoinPool相关推荐
- Java线程池ThreadPoolExecutor使用和分析
Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) Java线程池ThreadPoolExecutor使用和分析(三 ...
- Python 线程池 ThreadPoolExecutor(二) - Python零基础入门教程
目录 一.Python 线程池前言 二.Python 线程池 ThreadPoolExecutor 常用函数 1.线程池 as_completed 函数使用 2.线程池 map 函数使用 3.线程池 ...
- Python 线程池 ThreadPoolExecutor(一) - Python零基础入门教程
目录 一.Python 线程池前言 二.Python 线程池原理 三.Python 线程池 ThreadPoolExecutor 函数介绍 四.Python 线程池 ThreadPoolExecuto ...
- Java线程池ThreadPoolExecutor的实例
Java.util中的线程池和Spring框架对这个类的扩展 1.单独通过java里的ThreadPoolExecutor这个类,可以创建线程池,如果系统采用Spring框架设计,可以采用Thread ...
- java线程池执行器_Java线程池ThreadPoolExecutor的使用
Java线程池ThreadPoolExecutor的使用 ThreadPoolExecutor就是我们用来实现线程的一个执行器,它实现了Excutor和ExecutorService接口.Excuto ...
- c++ 线程池_JAVA并发编程:线程池ThreadPoolExecutor源码分析
前面的文章已经详细分析了线程池的工作原理及其基本应用,接下来本文将从底层源码分析一下线程池的执行过程.在看源码的时候,首先带着以下两个问题去仔细阅读.一是线程池如何保证核心线程数不会被销毁,空闲线程数 ...
- 线程池ThreadPoolExecutor的使用方法
private static ExecutorService exec = new ThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new Li ...
- Java线程池—ThreadPoolExecutor
2019独角兽企业重金招聘Python工程师标准>>> 为什么要使用线程池创建线程? 使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题 ...
- JUC(十)-线程池-ThreadPoolExecutor分析
ThreadPoolExecutor 应用 & 源码解析 文章目录 ThreadPoolExecutor 应用 & 源码解析 一.线程池相关介绍 1.1 为什么有了JDK提供的现有的创 ...
- 线程池ThreadPoolExecutor使用简介
2019独角兽企业重金招聘Python工程师标准>>> 一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: Th ...
最新文章
- 秒杀 高并发 类型系统方案设计
- 使用iis发布wcf服务
- MapReduce 计数器简介(转载自:http://www.tuicool.com/articles/qqyIBr)
- 【Python图像特征的音乐序列生成】解析ABC格式的文件(修改版)
- Java 按行读写文件(解决中文乱码)
- NSOperation队列实实现多线程
- 网页制作中点一张图片变成图片浏览式_网页不会做,那是画册看得少(上)
- CSS常用内容总结(二)
- python 利用 setup.py 手动安装django_chartit
- python读取txt每一行存入数组
- java 获取本机ip地址吗_java 获取本机ip地址
- latex添加标准文献:texmaker+bibtex+gbt7714-2005.bst
- 上座部佛教的佛陀略传
- js html监听ctrl v,js监听组合按键
- 1	About This Guide
- 一个可以为你的任何创作加速的神软件
- NeuralPS2021下载~论文总结~NeurlPS2021论文pdf
- 算法导论 直接寻址表
- 十张图深度剖析供应链金融业务模式
- 2018-09-03 KK日记,记一次JVM内存使用过多的诊断
热门文章
- 微信公众号 Markdown 编辑器
- 浏览器点击复制内容并打开微信
- 面试系列(九):商汤科技 深度学习平台C++研发
- 一键还原的GHO文件夹打开方法(转载)
- UIPATH 调用SAP BAPI
- latex图片的子标题放在中间
- 【Wing Loss】《Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks》
- LSD计算机控制人体大脑,科学家发现了LSD对大脑的影响
- Interpreter
- android标题栏尺寸,Android平台设计规范19条(轻松入门)