Executor框架
参考书籍:《Java并发编程的艺术》
从JDK5开始,工作单元和执行机制分离,工作单元包括Runnable和Callable,执行机制由Executor框架提供。
1 Executor框架简介
在HotSpot VM中,一个Java线程映射到一个操作系统线程。在上层,Java程序把应用分解成若干个任务,然后使用Executor框架将这些任务映射成固定数量的线程。在底层,操作系统内核将这些线程映射到硬件处理器。
1.1 Executor框架的结构
Executor框架由三大结构组成:
任务:包括被执行任务实现的接口:Runnable接口或Callable接口
任务的执行:ExecutorService接口继承自Executor,两个关键类ThreadPoolExecutoe和ScheduledThreadPoolExecutor
异步计算的接口:包括接口Future和实现它的FutureTask类
1.2 Executor框架的成员
1、ThreadPoolExecutor
ThreadPoolExecutor常用Executors工厂类来创建。
2、ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor使用工厂类Executors来创建。
3、Future接口
异步计算的结果用实现Future接口的FutureTask类来实现。
4、Runnable接口和Callable接口
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行,它们的区别是Runnable不会返回执行结果,Callable可以返回结果。
2 ThreadPoolExecutor
Executor框架最核心的类是ThreadPoolExecutor,他是线程池的实现类,七个主要参数已经在线程池的博客中提到过,通过Executors工具类,可以创建3种类型的ThreadPoolExecutor:
1、FixedThreadPool
2、SingleThreadExecutor
3、CachedThreadPool
2.1 FixedThreadPool
FixedThreadPool创建固定线程数,corePoolSize和maximumPoolSize都被设置成创建对象时的传入参数nThreads。FixedThreadPool使用无界队列来作为工作队列。
2.2 SingleThreadPool
SingleThreadPool的corePoolSize和maximumPoolSize都被设置成1,使用无界队列作为工作队列。
2.3 CachedThreadPool
CachedThreadPool的corePoolSize被设置为0,maximumPoolSize被设置为Integer.MAX_VALUE,keepAliveTime被设置为60秒。
3 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor用来在给定的延迟之后执行任务,或者定期执行任务,与Timer类似,但ScheduledThreadPoolExecutor功能更强大更灵活。Timer时单个后台线程,ScheduledThreadPoolExecutor可以指定多个后台线程。
3.1 ScheduledThreadPoolExecutor的执行机制
ScheduledThreadPoolExecutor使用DelayQueue无界队列作为任务队列,会把ScheduledFutureTask放到一个DelayQueue中,ScheduledFutureTask包含三个成员变量:
1、long型成员变量time,任务执行的具体时间
2、long型成员变量sequenceNumber,表示添加到ScheduledThreadPoolExecutor的序号
3、long型成员变量period,表示任务执行的间隔周期
DelayQueue工作队列中维护了PriorityQueue,排序时time小的放在前面,如果time相等,则根据sequenceNumber进行排序,小的排在前面。
4 FutureTask
FutureTask除了实现Future接口,还实现了Runnable接口,可以交给Executor执行。
4.1 FutureTask的使用
FutureTask的实现基于AQS,可以把FutureTask交给Executor执行,也可以通过submit来返回一个FutureTask,然后执行FutureTask的get方法或FutureTask的cancel方法,除此之外,还可以单独使用FutureTask。当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用FutureTask。