文章目录
Executor 框架介绍
1. 两级调度模型
由上面这张图片可以看出:
- 上层:Java多线程程序通常把应用分解为若干个任务,Executor框架)将这些任务映射为固定数量的线程
- 底层:操作系统内核将这些线程映射到硬件处理器上
2. Executor框架
Executor框架包含的主要的类与接口,如下图:
Executor框架的使用示意图如下:
过程分析:
-
主线程首先要创建实现
Runnable
或者Callable
接口的任务对象。Executors.callable(Runnable task)
或Executors.callable(Runnable task,Object resule)
将Runnable
封装为一个Callable
的方法。 -
然后可以把
Runnable
对象直接交给ExecutorService(ExecutorService.execute(Runnable command));
或者也可以把Runnable对象或Callable对象提交给ExecutorService执行。 -
如果执行
ExecutorService.submit(...)
,ExecutorService将返回一个实现Future接口的对象。由于FutureTask实现了Runnable,程序员也可以创建FutureTask,然后直接交给ExecutorService执行。
-
最后,主线程可以执行
FutureTask.get()
方法来等待任务执行完成。主线程也可以执行FutureTask.cancel(boolean mayInterruptIfRunning)
来取消此任务的执行。
3. Executor成员
-
ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。
-
ScheduledThreadPoolExecutor:ScheduledThreadPoolExecutor、SingleThreadScheduledExecutor
-
Future接口:Future接口和实现Future接口的
FutureTask
类用来表示异步计算的结果。 -
Runnable接口和Callable接口
下面是Executors提供的,把一个Runnable包装成一个Callable的API。public static Callable<Object> callable(Runnable task)
1. FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
上述代码可以看出, 这种线程池,核心线程池和最大线程池大小相同,且使用了无界阻塞队列(队列容量:Integer.MAX_VALUE
),这样无法执行的线程放入阻塞队列中。
流程图如下:
2.SingleThreadExecutor
代码如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
SingleThreadExecutor
的corePoolSize和maximumPoolSize被设置为1。其他参数与FixedThreadPool
相同。
工作图如下:
3. CachedThreadPool
CachedThreadPool是一个会根据需要创建新线程的线程池。代码如下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
工作流程如下:
工作流程阐述:
- 执行
SynchronousQueue.offer(Runnable task)
。如果当前maximumPool中有空闲线程正在执行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)
,那么主线程执行offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行,否则执行 2. - maximumPool中当前没有空闲线程时,没有线程执行
SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)
,此时CachedThreadPool会创建一个新线程执行任务。 - 在步骤2中新创建的线程将任务执行完后,会执行
SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)
。这个poll操作会让空闲线程最多在SynchronousQueue
中等待60秒钟。如果60秒钟内主线程提交了一个新任务(执行步骤1);否则,这个空闲线程将终止。
4. ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务。
- 运行机制如下图
DelayQueue是一个“无界”的”优先“、“阻塞”队列
-
实现
ScheduledThreadPoolExecutor会把待调度的任务(ScheduledFutureTask)放到一个DelayQueue中
ScheduledFutureTask主要包含3个成员变量:
- long型成员变量time,表示这个任务将要被执行的具体时间。
- long型成员变量sequenceNumber,表示这个任务被添加到ScheduledThreadPoolExecutor中的序号。
- long型成员变量period,表示任务执行的间隔周期。
DelayQueue将ScheduledFutureTask按照time从小到达进行排序,小的放在前面,如果时间相同,那么先提交的任务将被先执行。
线程1执行某个周期任务的4个步骤如下: