java Concurrent包学习笔记(一):ExecutorService
一、介绍
ExecutorService是java.util.concurrent包中的一个线程池实现接口。其有两个实现类:
1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能有效管理线程的调度,在执行大量异步线程时提高程序的性能。
/*** Creates a new {@code ThreadPoolExecutor} with the given initial* parameters.** @param corePoolSize the number of threads to keep in the pool, even* if they are idle, unless {@code allowCoreThreadTimeOut} is set* @param maximumPoolSize the maximum number of threads to allow in the* pool* @param keepAliveTime when the number of threads is greater than* the core, this is the maximum time that excess idle threads* will wait for new tasks before terminating.* @param unit the time unit for the {@code keepAliveTime} argument* @param workQueue the queue to use for holding tasks before they are* executed. This queue will hold only the {@code Runnable}* tasks submitted by the {@code execute} method.* @param threadFactory the factory to use when the executor* creates a new thread* @param handler the handler to use when execution is blocked* because the thread bounds and queue capacities are reached* @throws IllegalArgumentException if one of the following holds:<br>* {@code corePoolSize < 0}<br>* {@code keepAliveTime < 0}<br>* {@code maximumPoolSize <= 0}<br>* {@code maximumPoolSize < corePoolSize}* @throws NullPointerException if {@code workQueue}* or {@code threadFactory} or {@code handler} is null*/public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}
- corePoolSize:核心线程数,如果运行的线程少于corePoolSize,则创建新线程来执行新任务,即使线程池中的其他线程是空闲的
- maximumPoolSize:最大线程数,可允许创建的线程数,corePoolSize和maximumPoolSize设置的边界自动调整池大小:
- corePoolSize <运行的线程数< maximumPoolSize:仅当队列满时才创建新线程
- corePoolSize=运行的线程数= maximumPoolSize:创建固定大小的线程池
- keepAliveTime:如果线程数多于corePoolSize,则这些多余的线程的空闲时间超过keepAliveTime时将被终止
- unit:keepAliveTime参数的时间单位
- workQueue:保存任务的阻塞队列,与线程池的大小有关:
- 当运行的线程数少于corePoolSize时,在有新任务时直接创建新线程来执行任务而无需再进队列
- 当运行的线程数等于或多于corePoolSize,在有新任务添加时则选加入队列,不直接创建线程
- 当队列满时,在有新任务时就创建新线程
- threadFactory:使用ThreadFactory创建新线程,默认使用defaultThreadFactory创建线程
- handle:定义处理被拒绝任务的策略,默认使用ThreadPoolExecutor.AbortPolicy,任务被拒绝时将抛出RejectExecutorException
2)ScheduledThreadPoolExecutor:执行延迟任务和周期性任务。
二、ExecutorService种类
1、newSingleThreadExecutor
由数可知,创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,没有被执行的线程先排在等待队列中,而且先放入线程池的先执行
示例:
package executorservice.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** @author boshen* @date 2018/12/20*/ public class SingleThreadExecutorTest {class StudentThread implements Runnable{private String name;StudentThread(String name){this.name = name;}public void run(){System.out.println("学生:" + name + " 开始吃饭");try {Thread.sleep(3000);System.out.println("学生:" + name + " 吃完饭了");} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args){SingleThreadExecutorTest cb = new SingleThreadExecutorTest();ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.submit(cb.new StudentThread("张三"));executorService.submit(cb.new StudentThread("李四"));executorService.shutdown();} }
学生:张三 开始吃饭 学生:张三 吃完饭了 学生:李四 开始吃饭 学生:李四 吃完饭了
2、newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
示例:
package executorservice.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** @author boshen* @date 2018/12/20*/ public class FixedThreadPoolTest {class StudentThread implements Runnable{private String name;StudentThread(String name){this.name = name;}public void run(){System.out.println("学生:" + name + " 开始吃饭");try {Thread.sleep(2000);System.out.println("学生:" + name + " 吃完饭了");} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args){FixedThreadPoolTest cb = new FixedThreadPoolTest(); ExecutorService executorService = Executors.newFixedThreadPool(2);executorService.submit(cb.new StudentThread("张三"));executorService.submit(cb.new StudentThread("李四"));executorService.submit(cb.new StudentThread("王五"));executorService.submit(cb.new StudentThread("马六"));executorService.shutdown();} }
学生:李四 开始吃饭 学生:张三 开始吃饭 学生:李四 吃完饭了 学生:张三 吃完饭了 学生:王五 开始吃饭 学生:马六 开始吃饭 学生:马六 吃完饭了 学生:王五 吃完饭了
3、newCachedThreadPool
创建可缓存的线程池,如果线程池中的线程在60秒未被使用就将被移除,在执行新的任务时,当线程池中有之前创建的可用线程就重用可用线程,否则就新建一条线程
示例:
package executorservice.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** @author boshen* @date 2018/12/20*/ public class CachedThreadPoolTest {class StudentThread1 implements Runnable{private String name;StudentThread1(String name){this.name = name;}public void run(){System.out.println("学生:" + name + " 开始吃饭,线程名为:"+Thread.currentThread().getName());try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}class StudentThread2 implements Runnable{private String name;StudentThread2(String name){this.name = name;}public void run(){System.out.println("学生:" + name + " 开始吃饭,线程名为:"+Thread.currentThread().getName());try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args){CachedThreadPoolTest cb = new CachedThreadPoolTest();ExecutorService executorService = Executors.newCachedThreadPool();executorService.submit(cb.new StudentThread1("张三"));executorService.submit(cb.new StudentThread1("李四"));executorService.submit(cb.new StudentThread2("王五"));executorService.submit(cb.new StudentThread2("马六"));try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}executorService.submit(cb.new StudentThread1("赵七"));executorService.submit(cb.new StudentThread1("杨八"));executorService.shutdown();} }
学生:张三 开始吃饭,线程名为:pool-1-thread-1 学生:王五 开始吃饭,线程名为:pool-1-thread-3 学生:马六 开始吃饭,线程名为:pool-1-thread-4 学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:赵七 开始吃饭,线程名为:pool-1-thread-2 学生:杨八 开始吃饭,线程名为:pool-1-thread-1
由结果可知:
张三和李四执行时间为2秒,王五和马六执行时间为10秒,提交了前4个线程之后隔了4秒提交赵七和杨八的线程,这时候张三和李四已经执行完了。
所以张三的线程pool-1-thread-1继续执行杨八,李四的线程pool-1-thread-2继续执行赵七。并没有多创建出来pool-1-thread-5和pool-1-thread-6
4、newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行
- Executors.newScheduledThreadPool(int corePoolSize),corePoolSize表示线程容量。
- schedule(Callable/Runnable command,long initialDelay,TimeUnit unit):第一个参数任务,第二个参数表示执行任务前等待的时间,第三参数表示时间单位。
- scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):第一个参数表示周期线执行的任务,第二个参数表示第一次执行前的延迟时间,第三个参数表示任务启动间隔时间,第四个参数表示时间单位。虽然任务类型是Runnable但该方法有返回值ScheduledFuture。可以通过该对象获取线程信息。
- scheduleWithFixedDelay(Runnable command,long initialDelay,long period,TimeUnit unit):与scheduleAtFixedRate方法类似,不同的是第三个参数表示前一次结束的时间和下一次任务启动的间隔时间
示例
package executorservice.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;/*** @author boshen* @date 2018/12/20*/ public class ScheduledThreadPoolTest {class StudentThread implements Runnable{private String name;StudentThread(String name){this.name = name;}public void run(){try {System.out.println("学生:" + name + " 开始吃饭,线程名为:"+Thread.currentThread().getName());Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args){ScheduledThreadPoolTest cb = new ScheduledThreadPoolTest();ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);//当以下线程提交后要2秒后才执行,只执行一次executorService.schedule(cb.new StudentThread("张三"),2000, TimeUnit.MILLISECONDS);//当以下线程提交后要2秒后才执行,每3秒执行一次,直到调用了executorService.shutdown();executorService.scheduleWithFixedDelay(cb.new StudentThread("李四"),2,3,TimeUnit.SECONDS);try {Thread.sleep(20000);} catch (InterruptedException e) {e.printStackTrace();}executorService.shutdown();} }
学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:张三 开始吃饭,线程名为:pool-1-thread-1 学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:李四 开始吃饭,线程名为:pool-1-thread-2
三、ExecutorService的几个方法区别
1、execute(Runnable),无法取得返回值
public static void main(String[] args){ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.execute(new Runnable() {public void run() {System.out.println("该异步任务无返回值");}});executorService.shutdown();}
2、submit(Runnable),返回一个 Future 对象。这个 Future 对象可以用来检查 Runnable 是否已经执行完毕,但是也无法取得run方法里面想要返回的值因为run方法为void
public static void main(String[] args){ExecutorService executorService = Executors.newSingleThreadExecutor();Future future = executorService.submit(new Runnable() {public void run() {try {Thread.sleep(10000);System.out.println("该任务执行了10秒");} catch (InterruptedException e) {e.printStackTrace();}}});System.out.println("主线程中获取子线程的执行状态:如果返回null表示执行正确完成");try {System.out.println(future.get());//线程没有执行完之前,会阻塞在这里} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}executorService.shutdown();}
主线程中获取子线程的执行状态:如果返回null表示执行正确完成 该任务执行了10秒 null
3、submit(Callable),返回一个 Future 对象。这个 Future 对象可以返回线程中call方法里面return的对象
public static void main(String[] args){ExecutorService executorService = Executors.newSingleThreadExecutor();Future future = executorService.submit(new Callable() {public Object call() throws Exception {Thread.sleep(10000);System.out.println("该任务执行了10秒");return "call 返回的值";}});System.out.println("主线程中获取子线程的结果:");try {System.out.println(future.get());//线程没有执行完之前,会阻塞在这里} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}executorService.shutdown();}
主线程中获取子线程的结果: 该任务执行了10秒 call 返回的值
4、invokeAll(Collection<? extends Callable<T>> tasks),参数是加入线程池的所有Callable,返值是List<Future<T>>,表示返回执行后的一系列Callable的执行结果
package executorservice.demo;import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;/*** @author Administrator* @date 2018/12/27*/ public class InvokeAllTest {class StudentThread implements Callable{private String name;StudentThread(String name){this.name = name;}public Object call() throws Exception{System.out.println("学生:" + name + " 开始吃饭,线程名为:"+Thread.currentThread().getName());return "result: 学生"+name+"吃完饭了";}}public static void main(String[] args){InvokeAllTest invokeAllTest = new InvokeAllTest();ExecutorService executorService = Executors.newCachedThreadPool();List<Callable<String>> callables = new ArrayList<Callable<String>>();callables.add(invokeAllTest.new StudentThread("张三"));callables.add(invokeAllTest.new StudentThread("李四"));callables.add(invokeAllTest.new StudentThread("王五"));callables.add(invokeAllTest.new StudentThread("马六"));try { List<Future<String>> futures = executorService.invokeAll(callables);for(Future<String> future:futures){System.out.println(future.get());}} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}executorService.shutdown();} }
学生:张三 开始吃饭,线程名为:pool-1-thread-1 学生:王五 开始吃饭,线程名为:pool-1-thread-3 学生:李四 开始吃饭,线程名为:pool-1-thread-2 学生:马六 开始吃饭,线程名为:pool-1-thread-4 result: 学生张三吃完饭了 result: 学生李四吃完饭了 result: 学生王五吃完饭了 result: 学生马六吃完饭了
四、ExecutorService 关闭
ExecutorService 的 shutdown() 方法。并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭。在 shutdown() 被调用之前所有提交给 ExecutorService 的任务都被执行。
如果你想要立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这样会立即尝试停止所有执行中的任务,并忽略掉那些已提交但尚未开始处理的任务。无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。
java Concurrent包学习笔记(一):ExecutorService相关推荐
- java concurrent包的学习(转)
java concurrent包的学习(转) http://my.oschina.net/adwangxiao/blog/110188 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常 ...
- Java快速入门学习笔记1 | Eclipse使用
有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...
- Java 8 实战学习笔记
Java 8 实战学习笔记 @(JAVASE)[java8, 实战, lambda] 文章目录 Java 8 实战学习笔记 参考内容 Lambda表达式 Lambda环绕执行模式(抽离步骤) 原始代码 ...
- JAVA 第二周学习笔记
JAVA第二周学习笔记 一.变量 1.变量的本质 2.变量的三大要素 a.变量名: b.变量值: c.变量类型: 3.变量的定义和使用 4.课后小练习: 5.变量的定义和使用 二.运算符 1.赋值运算 ...
- Java基础篇 学习笔记
List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...
- Java微服务学习笔记(一):微服务架构的概念理解
Java微服务学习笔记 Tips:入门学习时粗略整理,仅供参考 (一):架构的基础理解 文章目录 Java微服务学习笔记 前言 一.微服务是什么? 二.常用开源微服务框架演化 1. Dubbo 2. ...
- java/android 设计模式学习笔记(7)---装饰者模式
这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是 ...
- java/android 设计模式学习笔记(1)--- 单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- java.util.List学习笔记
概述 在Java中,List是一种特殊的集合结构,即:List是一种有序的集合.在List接口的实现中,需要提供根据列表下表对元素进行操作的方法,包括:插入,删除,查询和修改等: List一般允许重复 ...
最新文章
- arcgis api for flex 开发入门(九)webservices 的使用
- javascript-tab切换效果
- input按钮中的onclick事件
- 为什么0的补码形式只有一种?
- [转] 最近点对距离问题
- zookeeper命令行操作
- 【今日CS 视觉论文速览】 25 Jan 2019
- PAT乙级 1005 继续(3n+1)猜想 (25分)
- 车险对方全责理赔要自己垫付吗?
- ImageLoader
- Okhttp之RealConnection建立链接简单分析
- VectorDraw web library javascript Crack
- ID3算法的Python实现
- Python统计列表元素出现次数
- 关于雅虎邮箱的Foxmail,outlook设置。
- cas:1092775-62-6 ; (ir[dfcf3ppy]2(bpy))pf6热延迟荧光材料TADF
- matlab检验矩阵是否可逆,有限域上矩阵是否可逆的检验
- 炔烃/NH2/COOH/NHS ester/N3/酰胫/马来酰亚胺/四嗪/DBCO/C12/鬼笔环肽等基团修饰BODIPY558/568
- 机关里看似讨巧实则毁人设的8种行为
- 如何压缩图片到500KB?怎么压缩图片到指定大小?
热门文章
- 使用gcc编译c语言程序,用GCC编译C ++程序
- oracle数据库swap占用率高,Oracle数据库所在服务器swap严重
- 常见WEB漏洞描述及修复建议(可收藏写报告用)-句芒安全实验室
- zabbix远程mysql_zabbix action 执行远程命令
- 可以发外链的网站_SEO分享:网站推广的四大推广方法
- android分辨率hdpi,Android资源 - 哪些分辨率应该进入hdpi,ldpi,mdpi和xhdpi目录
- php+mkdate,PHP时间工具种
- mysql查询条件_mysql条件查询,最简单的一种,你知道吗?
- 高中计算机网络安全教案,浙教版高中信息技术教案信息安全
- 计算机组装图示,台式机组装教程-台式机DIY装机教程示意图(自己动手组装电脑)...