【Java并发】Executor框架
Executor框架简介
Java的线程既是工作单元,也是执行机制。从JDK5开始,把工作单元和执行机制分离开来。
Executor框架由3大部分组成
任务。
被执行任务需要实现的接口:Runnable接口或Callable接口
异步计算的结果。Future接口和FutureTask类。
任务的执行。两个关键类ThreadPoolExecutor和SeheduledThreadPoolExecutor。
任务
Runnable接口
不含有运行结果
- public interface Runnable {
- public abstract void run();
- }
Callable接口
含有运行结果
- public interface Callable<V> {
- V call() throws Exception;
- }
Runnable与Callable的区别
Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。
Future接口
Future接口代表异步计算的结果,通过Future接口提供的方法可以查看异步计算是否执行完成,或者等待执行结果并获取执行结果,同时还可以取消执行。
- public interface Future<V> {
- boolean cancel(boolean mayInterruptIfRunning);//取消任务
- boolean isCancelled();//是否取消了
- boolean isDone();//任务是否完成
- //获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成
- V get() throws InterruptedException, ExecutionException;
- //等待一段时间尝试获取执行结果,
- V get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException;
- }
一个使用Runnable的简单例子
- import java.util.concurrent.*;
- public class Test {
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- final ExecutorService exec = Executors.newFixedThreadPool(5);
- Runnable task = new Runnable() {
- public void run() {
- try {
- System.out.println(Thread.currentThread().getName() + " is running");
- Thread.sleep(1000 * 10);//休眠指定的时间,此处表示该操作比较耗时
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- exec.submit(task);
- //关闭线程池
- exec.shutdown();
- }
- }
一个使用Callable的简单例子
- import java.util.concurrent.*;
- public class Test {
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- final ExecutorService exec = Executors.newFixedThreadPool(5);
- Callable<String> call = new Callable<String>() {
- public String call() throws Exception {
- Thread.sleep(1000 * 10);//休眠指定的时间,此处表示该操作比较耗时
- return "Other less important but longtime things.";
- }
- };
- Future<String> task = exec.submit(call);
- //重要的事情
- System.out.println("Let's do important things. start");
- Thread.sleep(1000 * 3);
- System.out.println("Let's do important things. end");
- //不重要的事情
- while(!task.isDone()){
- System.out.println("still waiting....");
- Thread.sleep(1000 * 1);
- }
- System.out.println("get sth....");
- String obj = task.get();
- System.out.println(obj);
- //关闭线程池
- exec.shutdown();
- }
- }
运行结果
- Let's do important things. start
- Let's do important things. end
- still waiting....
- still waiting....
- still waiting....
- still waiting....
- still waiting....
- still waiting....
- still waiting....
- get sth....
- Other less important but longtime things.
任务的执行机制
ThreadPoolExecutor
ThreadPoolExecutor是Executor框架最核心的类,是线程池的实现类。
核心配置参数包括
corePoolSize:核心线程池的大小
maximumPoolSize:最大线程池的大小
BlockingQueue:暂时保存任务的工作队列
RejectedExecutionHandler:当ThreadPoolExecutor已经饱和时(达到了最大线程池大小且工作队列已满)将执行的Handler。
- public ThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue<Runnable> workQueue) {
- this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
- Executors.defaultThreadFactory(), defaultHandler);
- }
可以创建3种类型的ThreadPoolExecutor。
FixedThreadPool
SingleThreadExecutor
CachedThreadPool
1.FixedThreadPool
FixedThreadPool是固定线程数的线程池,最多线程池中有nThreads个线程。
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads, //nThreads为固定线程数
- 0L, TimeUnit.MILLISECONDS, //空闲线程的等待时间为0ms,表示立刻被终止
- new LinkedBlockingQueue<Runnable>()); //工作队列
- }
FixedThreadPool的execute()方法内部执行过程
当新任务被提交时,如果当前运行线程数小于nTheads,创建新线程执行任务
如果当前运行线程数等于设置的最大线程数nThreads,将新任务加入到工作队列LinkedBlockingQueue中
线程执行完任务后会反复从LinkedBlockingQueue中获取新任务执行
LinkedBlockingQueue中没有新任务,线程空闲,线程将被终止。
注意点:
由于工作队列使用的是无界队列LinkedBlockingQueue,FixedThreadPool不会拒绝任务(不会调用RejectedExecutionHandler.rejectedExecution()方法)。
2.SingleThreadExecutor
SingleThreadExecutor是FixedThreadPool的特例,线程池中线程的固定数量为1,即最多有一个线程。
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1, //nThreads为固定线程数
- 0L, TimeUnit.MILLISECONDS, //空闲线程的等待时间为0ms,表示立刻被终止
- new LinkedBlockingQueue<Runnable>())); //工作队列
- }
SingleThreadExecutor的execute()方法内部执行过程与注意事项可参考FixedThreadPool的。
3.CachedThreadPool
CachedThreadPool是根据需要创建新线程的线程池。
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE, //coolPoolSize为0,maxinumPoolSize为Integer.MAX_VALUE
- 60L, TimeUnit.SECONDS, //空闲线程的等待时间,空闲60s后被终止
- new SynchronousQueue<Runnable>()); //工作队列
- }

CachedThreadPool的execute()方法的内部运行过程
当新任务被提交时,主线程将任务插入到工作队列中(SynchronousQueue的offer()方法),如果线程池有空闲线程在等待任务,新任务交给空闲线程处理。
如果线程池中没有在等待任务的空闲线程,创建新线程执行任务
线程执行完任务后,等待60s(SynchronousQueue.poll(60, TimeUnit.SECONDS)方法),如果没有等待新任务,线程终止
SynchronousQueue是一个没有容量的BlockingQueue。每一个插入操作必须等待另一个线程的移除操作。
CachedThreadPool使用SynchronousQueue,把主线程提交的任务传递给空闲线程。
注意点:
CachedThreadPool的线程池是无解的,没有限制数量,如果主线程提交任务的速度高于线程处理任务的速度,将不断创建新线程。
极端情况下,会因创建过多线程耗尽CPU和内存。
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor主要用于定时任务(定期执行,给定延迟后执行)
执行方式
1.scheduleAtFixedRate
任务按照固定周期执行,比如设定每10分钟执行一次,第8分钟时候执行了第一次,后续执行时间点为第18分钟,第28分钟,第38分钟
- public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, //任务
- long initialDelay, //初始延迟
- long period, //任务执行周期
- TimeUnit unit)
2.scheduleWithFixedDelay
任务按照固定延迟执行,比如设定延迟时间为10是分钟,第8分钟时候执行了第一次,任务执行完成后,再等待10分钟,执行下一次。如果任务执行了2分钟,则下一次为第20分钟
- public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,//任务
- long initialDelay, //初始延迟
- long delay, //任务执行延迟
- TimeUnit unit)
实现原理
数据结构
ScheduledThreadPoolExecutor:定时任务执行器
DelayQueue:使用DelayQueue作为任务队列,保存待调度的任务,任务按照执行的时间点排序。DelayQueue内部是用PriorityQueue实现。
ScheduledFutureTask:待调度任务。
ScheduledFutureTask的成员变量:
time:任务将被执行的具体时间
sequenceNumber:任务序号,time相同时,序号小的先执行
period:任务执行的间隔周期
运行机制
ScheduledThreadPoolExecutor内部运行过程
线程从DelayQueue中获取到到期的ScheduledFutureTask,到期是指time大于等于当前时间。
执行任务ScheduledFutureTask
修改ScheduledFutureTask的time为下次要执行的时间,放回到DelayQueue中
【Java并发】Executor框架的更多相关文章
- 构建自己的Java并发模型框架
Java的多线程特性为构建高性能的应用提供了极大的方便,可是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题须要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. 另外.应用逻辑和线程逻辑 ...
- 构建Java并发模型框架
Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误.另外,应用逻辑和线程逻辑纠 ...
- Java并发模型框架
构建Java并发模型框架 Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. ...
- Java的Executor框架和线程池实现原理
Java的Executor框架 1,Executor接口 public interface Executor { void execute(Runnable command); } Executor接 ...
- JAVA的Executor框架
Executor框架分离了任务的创建和执行.JAVA SE5的java.util.concurrent包中的执行器(Executor)管理Thread对象,从而简化了并发编程.Executor引入了一 ...
- Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...
- java并发编程框架 Executor ExecutorService invokeall
首先介绍两个重要的接口,Executor和ExecutorService,定义如下: public interface Executor { void execute(Runnable command ...
- JAVA并发-Executor
结构 类继承图: 上面的各个接口/类的关系和作用: Executor 执行器接口,也是最顶层的抽象核心接口, 分离了任务和任务的执行. ExecutorService 在Executor的基础上提供了 ...
- Java并发包下锁学习第二篇Java并发基础框架-队列同步器介绍
Java并发包下锁学习第二篇队列同步器 还记得在第一篇文章中,讲到的locks包下的类结果图吗?如下图: 从图中,我们可以看到AbstractQueuedSynchronizer这个类很重要(在本 ...
- Java的Executor框架和线程池实现原理(转)
ExecutorService接口继承自Executor接口,定义了终止.提交,执行任务.跟踪任务返回结果等方法 1,execute(Runnable command):履行Ruannable类型的任 ...
随机推荐
- jQery 操作CSS
jQuery操作CSS也是很方便的,咱先看看这几个常用的方法: addClass():向一个元素添加一个或者多个类. removeClass():从一个元素中删除一个类或多个类. toggleClas ...
- Google I/O 2013 – Volley: Easy, Fast Networking for Android
1.什么是volley Volley是Ficus Kirpatrick在Gooogle I/O 2013发布的一个处理和缓存网络请求的库,能使网络通信更快,更简单,更健壮.Volle ...
- 【BZOJ1283/3550】序列/[ONTAK2010]Vacation 最大费用流
[BZOJ1283]序列 Description 给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为 的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和 ...
- mybatis的dao的注解
import com.jianwu.domain.metting.model.CallPreMember;import com.jianwu.domain.metting.model.CallPreM ...
- 手动爬虫之京东笔记本栏(ptyhon3)
import urllib.request as ur import urllib.error as ue import re # 目标网址 url = 'https://list.jd.com/li ...
- java 如何将实体bean和map互转化 (利用Introspector内省)
// 将一个map对象转化为bean public static void transMap2Bean(Map<String, Object> map, Object obj) { try ...
- delphi ---break,exit,continue等跳出操作的区别
1.break 强制退出最近的一层循环(注意:只能放在循环里:而且是只能跳出最近的一层循环),用于从for.while.repeat语句中强制退出 2.continue 用于从for.while.re ...
- POJ 1423 Greatest Common Increasing Subsequence【裸LCIS】
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1423 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- Oracle Schema Objects——Tables——Table Compression
Oracle Schema Objects Table Compression 表压缩 The database can use table compression to reduce the amo ...
- xshell 没有反应---Xshell按ctrl+s界面无反应的解决办法
在用Xshell管理远程服务器,特别是在用vi编辑配置文件时,总是习惯的用ctrl+s想要保存文件,然后就悲剧了.xsell就再也没有返应只能关了重新打开.但原来修改的文件算是报废了. 在网上搜索了一 ...