Java并发编程--4.Executor框架
简介
Executor框架是启动,管理线程的API, 它的内部实现是线程池机制,它有很多好处,比如使任务提交和任务执行解耦合,防止this逃逸;
它的主要API包括: Executor, Executors, ExecutorService , Callable, Future, CompletionService, ThreadPoolExecutor
ExecutorService 生命周期
一个Executor的生命周期有三种状态: 运行状态,关闭状态,终止状态; ExecutorService中添加了生命周期管理的方法 Executor创建时, 处于运行状态; 当调用shutdown()后,处于关闭状态,停止接受新的线程,并执行已接受的线程任务; 所有任务执行完成后,处于终止状态
Executors 创建线程池
newFixedThreadPool : 创建定长的线程池, 最多有固定数量的线程, 如果还有创建新的线程,需要放到队列中等待, 直到有线程从池中移出
newCachedThreadPool :可缓存的线程池, 如果现有线程没有可用,则创建一个新线程并添加到池中。60 秒钟未被使用的线程会被移除
newSingleThreadExecutor : 只创建一个工作线程, 当工作线程异常结束, 会重新创建一个线程
newScheduledThreadPool: 创建定长的线程池, 支持定时的任务执行
线程池执行Runnable的例子
public class MyExecutors {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++){
executorService.execute(new MyRunnable());
} executorService.shutdown();
} } class MyRunnable implements Runnable { @Override
public void run() {
System.out.println(Thread.currentThread().getName() + "被调用");
}
}
Callable和Future 携带结果的任务
Callable: 带有返回值的任务
Future: 保存一个任务执行后的结果
下面给出一个例子:
public class MyCallable {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>(); //创建10个任务并执行
for (int i = 0; i < 10; i++){
Future<String> future = executorService.submit(new TaskWithResult(i)); //将任务执行结果存储到List中
resultList.add(future);
} //遍历任务的结果
for (Future<String> fs : resultList){
try{
while(!fs.isDone());//Future返回如果没有完成,则一直循环等待,直到Future返回完成
System.out.println(fs.get()); //打印各个线程(任务)执行的结果 }catch(Exception e){
e.printStackTrace();
}finally{
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务
executorService.shutdown();
}
}
}
} class TaskWithResult implements Callable<String>{
private int id; public TaskWithResult(int id){
this.id = id;
} /**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,
* 则该方法自动在一个线程上执行
*/
public String call() throws Exception {
System.out.println("call()方法被自动调用!!! " + Thread.currentThread().getName());
//该返回结果将被Future的get方法得到
return "call()方法被自动调用,任务返回的结果是:" + id + " " + Thread.currentThread().getName();
}
}
CompletionService完成服务,打包结果
任意任务完成后就把其加到结果中, 调用CompletionService的take()方法,返回 按任务的完成顺序 封装的结果, 像是一个打包的Future
下面给出一个例子
public class MyCompletionService {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool(); //构造函数传入一个Executor
CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService); //创建10个任务并执行
for (int i = 0; i < 10; i++){
if(!executorService.isShutdown()) {
//由CompletionService执行任务
completionService.submit(new Result0());
} } //把多个任务的结果加起来
String result = "2_";
try {
for (int i = 0; i < 10; i++) {
// 如果任务未完成,则该任务的take()会阻塞
String s = completionService.take().get();
result += s;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} //输出最终的计算结果
System.out.println(result); try{ }catch(Exception e){
e.printStackTrace();
}finally{
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务
executorService.shutdown();
}
}
} class Result0 implements Callable<String>{ /**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,
* 则该方法自动在一个线程上执行
*/
public String call() throws Exception {
//该返回结果将被Future的get方法得到
return "1";
}
}
ThreadPoolExecutor自定义线程池
ThreadPoolExecutor 有多个构造方法创建线程池,下面是一个构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
参数说明:
corePoolSize:线程池中所保存的核心线程数,包括空闲线程。
maximumPoolSize:池中允许的最大线程数。
keepAliveTime:线程池中的空闲线程所能持续的最长时间。
unit:持续时间的单位。
workQueue:任务执行前保存任务的队列,仅保存由execute方法提交的Runnable任务。
添加任务的过程
1、池中的线程数量少于corePoolSize,即使线程池中有空闲线程,也会创建一个新的线程来执行新添加的任务; 2、池中的线程数量大于等于corePoolSize,但缓冲队列未满,则将新添加的任务放到workQueue中,
线程池中有线程空闲出来后依次将缓冲队列中的任务交付给空闲的线程执行;
如果里面有线程的空闲时间超过了keepAliveTime,就将其移除线程池 3、池中的线程数量大于等于corePoolSize,且缓冲队列workQueue已满,但线程数量小于maximumPoolSize,则会创建新的线程来处理被添加的任务; 4、如果线程池中的线程数量等于了maximumPoolSize,通过设置饱和策略处理,也即是设置6个参数构造函数的第6个参数RejectedExecutionHandler
总体流程就是: 先看线程池中的线程数量是否大于corePoolSize,再看缓冲队列workQueue是否满,最后看线程池中的线程数量是否大于maximumPoolSize
排队策略
无界队列: 采用预定义容量的LinkedBlockingQueue,理论上是该缓冲队列可以对无限多的任务排队,newFixedThreadPool采用的便是这种策略
有界队列: 一般使用ArrayBlockingQueue制定队列的长度
同步移交 :SynchronousQueue 跳过队列,将任务从生产者直接交给消费者,如果不存在可用于立即运行任务的线程,会构造一个新的线程来处理新添加的任务,通常是无界的,newCa chedThreadPool采用的便是这种策略。
使用案例
public class MyThreadPoolExecutor {
public static void main(String[] args){
//创建等待队列
BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20); //创建线程池,池中保存的线程数为3,允许的最大线程数为5
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue); //创建七个任务
Runnable t1 = new MyThread();
Runnable t2 = new MyThread();
Runnable t3 = new MyThread();
Runnable t4 = new MyThread();
Runnable t5 = new MyThread();
Runnable t6 = new MyThread();
Runnable t7 = new MyThread(); //每个任务会在一个线程上执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7); //关闭线程池
pool.shutdown();
}
} class MyThread implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
控制台输出:
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-3正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-3正在执行。。。
pool-1-thread-2正在执行。。。
可以看出7个任务在3个线程上执行
Java并发编程--4.Executor框架的更多相关文章
- Java 并发编程 -- Fork/Join 框架
概述 Fork/Join 框架是 Java7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.下图是网上流传的 Fork Join 的 ...
- Java并发——线程池Executor框架
线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...
- java并发编程:Executor、Executors、ExecutorService
1.Executor和ExecutorService Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable comma ...
- Java并发编程之——Amino框架
Amino框架是一个采用无锁方式实现并行计算的框架,可惜的是,网上关于Amino框架的介绍甚少.根据所掌握的资料,稍微总结一下: 1. 锁机制到无锁机制 锁机制可以确保程序和数据的线程安全,但是锁是一 ...
- Java并发编程--Fork/Join框架使用
上篇博客我们介绍了通过CyclicBarrier使线程同步,可是上述方法存在一个问题,那就是假设一个大任务跑了2个线程去完毕.假设线程2耗时比线程1多2倍.线程1完毕后必须等待线程2完毕.等待的过程线 ...
- java并发编程-Executor框架
Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion ...
- Java 并发编程——Executor框架和线程池原理
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...
- 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结
<Java并发编程实战>和<Java并发编程的艺术> Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...
- (转)java并发编程--Executor框架
本文转自https://www.cnblogs.com/MOBIN/p/5436482.html java并发编程--Executor框架 只要用到线程,就可以使用executor.,在开发中如果需要 ...
随机推荐
- POJ 1061 青蛙的约会 扩展欧几里德--解不定方程
青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 81606 Accepted: 14116 Descripti ...
- python学习之老男孩python全栈第九期_数据库day003 -- 作业
数据库: class: course: student: teacher: score: /* Navicat Premium Data Transfer Source Server : local ...
- Spring 中面向AOP之一系列做法
Spring的AOP实现是通过集成AspectJ框架实现的. 想必这句话大家都知道了吧,不知道也没关系,最起码你现在知道了. 四种实现方案,接下来我们一一去揭开它的神秘的面纱....... 第一种(伪 ...
- shiro标签的使用
guest标签 用户没有身份验证时显示相应信息,即游客访问信息. user标签 用户已经身份验证/记住我登录后显示相应的信息. authenticated标签 用户已经身份验证通过, ...
- maven 安装下载与配置 代理设置 《解决下载慢问题》
maven:下载地址http://mirror.bit.edu.cn/apache/maven/maven-3/ 解压之后配置环境 %maven_home% d:\*****path 中添加 %ma ...
- Xcode 7安装KSImageNamed 不启作用
1. 到 ~/Library/Developer/Xcode/Plug-ins 删除KSImageNamed.xcplugin 2. 在~/Library/Developer/Xcode/Plug- ...
- 深入解析 ERP 计划的各个层次
ERP 生产计划管理按照 ERP 计划的层次主要分为:经营规划.销售和运作规划.主生产计划.物料需求计划.能力需求计划.执行能力计划.执行物料计划等. 经营规划是企业的战略规划,用于确定企业经营目标和 ...
- 递归方程T(n)=aT(n/b)+f(n)之通用解法
,b>1为常数,f(n)为函数,T(n)=aT(n/b)+f(n)为非负数,令x=logba: 1. f(n)=o(nx-e),e>0,那么T(n)=O(nx). 2. ...
- Python 操作数据库pymysql
import pymysql #添加数据 conn , user='root', passwd='', db='yyy') #更改获取数据结果的数据类型,默认是元组,可以改为字典等:#cursor=c ...
- Android组件系列----Activity的生命周期
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...