Executor框架详解

java的线程既是工作单元,也是执行机制。从jdk5开始,把工作单元与执行机制分离开来。工作单元包括Runnable和Callable,而执行机制由Executor框架提供。这样一来Executor是基于生产者消费者模式的,提交任务的操作相当于生成者,执行任务的线程相 当于消费者。

一、Executor框架的两级调度模型

在HotSpot VM的模型中,JAVA线程被一对一映射为本地操作系统线程。JAVA线程启动时会创建一个本 地操作系统线程,当JAVA线程终止时,对应的操作系统线程也被销毁回收,而操作系统会调度所有线程 并将它们分配给可用的CPU。

在上层,JAVA程序会将应用分解为多个任务,然后使用应用级的调度器(Executor)将这些任务映射成 固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。





1、从类图上看,Executor接口是异步任务执行框架的基础,该框架能够支持多种不同类型的任务执行策略。Executor接口就提供了一个执行方法,任务是Runnbale类型,不支持Callable类型。

public interface Executor {
void execute(Runnable command);
}

2、ExecutorService接口实现了Executor接口,主要提供了关闭线程池和submit方法:

public interface ExecutorService extends Executor {
List<Runnable> shutdownNow();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
}

另外该接口有两个重要的实现类:ThreadPoolExecutor与ScheduledThreadPoolExecutor。其中ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务;而 ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行任务,或者定期执行命令。

在上一篇文章中,我是使用ThreadPoolExecutor来通过给定不同的参数从而创建自己所需的线程池,但是在后面的工作中不建议这种方式,推荐使用Exectuors工厂方法来创建线程池

Executor框架使用示意图



1、主线程首先要创建实现Runnable或者Callable接口的任务对象工具类Executors,可以把一个Runnable对象封装为一个Callable对象(Executors.callable(Runnable task) 或者 Executors.callable(Runnable task,Object resule))。

2、然后可以把Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command));或者可以把Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task) 或 ExecutorService.submit(Callable task))。

3、如果执行ExecutorService.submit(…),ExecutorService将返回一个实现Future接口的对象(FutureTask)。由于FutureTask实现了Runnable,程序员也可以创建FutureTask,然后直接交给ExecutorService执行。

4、最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。

Executor框架的实现ThreadPoolExecutor

Executors可以创建3种类型的ThreadPoolExecutor:SingleThreadExecutorFixedThreadExecutorCachedThreadPool

1、SingleThreadExecutor:单线程线程池

ExecutorService threadPool = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

我们从源码来看可以知道,单线程线程池的创建也是通过ThreadPoolExecutor,里面的核心线程数和线 程数都是1,并且工作队列使用的是无界队列。由于是单线程工作,每次只能处理一个任务,所以后面所 有的任务都被阻塞在工作队列中,只能一个个任务执行。

2、FixedThreadExecutor:固定大小线程池

ExecutorService threadPool = Executors.newFixedThreadPool(5);

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

这个与单线程类似,只是创建了固定大小的线程数量。

3、CachedThreadPool:无界线程池

ExecutorService threadPool = Executors.newCachedThreadPool();

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

无界线程池意味着没有工作队列,任务进来就执行,线程数量不够就创建,与前面两个的区别是:空闲 的线程会被回收掉,空闲的时间是60s。这个适用于执行很多短期异步的小程序或者负载较轻的服务 器。

最新文章

  1. iOS Start developing ios apps (OC) pdf
  2. 图解JVM的类加载机制(详细版)
  3. jQuery学习笔记(三)jQuery中的事件
  4. POJ 2838 单调队列
  5. 理解Bitcode
  6. leetcde37. Sudoku Solver
  7. 异步等待(ManualResetEvent
  8. windows10 qt5 mingw32编译cryptopp563
  9. python之setattr,getattr,hasattr
  10. 关于GestureDetector.OnGestureListener的onScroll参数distance问题
  11. 第1天:CSS基本样式
  12. 【转】Wi-Fi 20mhz 和 40mhz 频段带宽的区别是什么?
  13. 一次saltstack环境变量的坑
  14. OAF中的TableLayout 高级表格
  15. 开源Web自动化测试工具Selenium IDE
  16. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:建立一个EF数据模型
  17. 05: api认证
  18. .NET MVC请求流程
  19. VSCode编辑器编写Python代码
  20. 使用Jquery Viewer 展示图片信息

热门文章

  1. 国产DP4398 兼容替代CS4398 24Bit 192KHz数模转换芯片
  2. Oracle函数NULLIF
  3. windows11上面打开HEIC文件的有效方法
  4. [原创] CSS自定义IOS苹果,Android安卓的CheckBox 效果,可以根据文字大小变化而变化,内框显示文字,另外可自定大小,自定颜色
  5. tomcat前后端项目部署及调优
  6. 看K线学炒股(8.5)
  7. bottle库上传文件
  8. 使用HttpClient4.5 使用MultipartEntityBuilder 类发送 multipart/formdata 格式给第三方接口 失败的原因
  9. LaTex【五】latex导入中文包,支持中文显示
  10. ORACLE 创建只读用户