【并发编程】- ThreadPoolExecutor篇
-
Executor框架
-
Executor
框架的两级调度模型(基于HotSpot)- 在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(
Executor
框架)将这些任务映射为固定数量的线程; - 在底层,操作系统内核将这些线程映射到硬件处理器上。
任务的两级调度模型
- 在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(
- 结构
- 3大部分
- 任务。包括被执行任务需要实现的接口:
Runnable
接口或Callable
接口。 - 任务的执行。包括任务执行机制的核心接口
Executor
,以及继承自Executor
的ExecutorService
接口。Executor
框架有两个关键类实现了ExecutorService
接口(ThreadPoolExecutor
和ScheduledThreadPoolExecutor
)。 - 异步计算的结果。包括接口
Future
和实现Future
接口的FutureTask
类。
- 任务。包括被执行任务需要实现的接口:
类与接口
- 3大部分
- 成员
-
ThreadPoolExecutor
:通常使用工厂类Executors
来创建。-
SingleThreadExecutor
- 使用单个线程,适用于
需要保证顺序地执行
各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
- 使用单个线程,适用于
-
FixedThreadPool
- 使用固定线程数,适用于
负载比较重
的服务器。
- 使用固定线程数,适用于
-
CachedThreadPool
- 会根据需要创建新线程,大小无界,适用于
执行很多的短期异步任务
的小程序,或者是负载较轻
的服务器。
- 会根据需要创建新线程,大小无界,适用于
-
-
ScheduledThreadPoolExecutor
:通常使用工厂类Executors
来创建.- 包含若干个线程的ScheduledThreadPoolExecutor。
- 创建固定个数线程,适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
- 只包含一个线程的ScheduledThreadPoolExecutor。
- 创建单个线程,适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景。
- 包含若干个线程的ScheduledThreadPoolExecutor。
-
Future
接口- FutureTask实现类,表示异步计算的结果。
-
Runnable
接口和Callable
接口-
Runnable
不会返回结果。 -
Callable
可以返回结果。
-
-
-
ThreadPoolExecutor
详解 - 4个组件
-
corePool
:核心线程池的大小。 -
maximumPool
:最大线程池的大小。 -
BlockingQueue
:用来暂时保存任务的工作队列。 -
RejectedExecutionHandler
:当ThreadPoolExecutor
已经关闭或ThreadPoolExecutor
已经饱和时(达到了最大线程池大小且工作队列已满),execute()
方法将要调用的Handler
。
-
- 3种ThreadPoolExecutor
-
FixedThreadPool
- 可重用固定线程数的线程池。
- 使用无界队列
LinkedBlockingQueue
作为线程池的工作队列(队列的容量为Integer.MAX_VALUE。
-
SingleThreadExecutor
- 使用单个
worker
线程的Executor
。 - 使用无界队列
LinkedBlockingQueue
作为线程池的工作队列(队列的容量为Integer.MAX_VALUE。
- 使用单个
-
CachedThreadPool
- 会根据需要创建新线程的线程池。
- 使用无容量的SynchronousQueue作为线程池的工作队列。
-
-
ScheduledThreadPoolExecutor
详解- ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务
- ScheduledThreadPoolExecutor的执⾏主要分为两⼤部分
- 当调⽤ScheduledThreadPoolExecutor的scheduleAtFixedRate()fang法或者scheduleWith-FixedDelay()方法时,会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFutur接⼝的ScheduledFutureTask
- 线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务
ScheduledThreadPoolExecutor 运行机制图
-
Java里的阻塞队列
- JDK 7提供了7个阻塞队列
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
- LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
- DelayQueue:一个使用优先级队列实现的无界阻塞队列。
- SynchronousQueue:一个不存储元素的阻塞队列。
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
- JDK 7提供了7个阻塞队列
-
ArrayBlockingQueue:数组有界阻塞队列,默认线程非公平的访问队列,公平性是使用可重入锁实现
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
- LinkedBlockingQueue:链表有界阻塞队列,默认长度Integer.Max_VALUE
- PriorityBlockingQueue:是一个支持优先级的无界阻塞队列。默认情况下元素采取用然顺序升序排列
- DelayQueue是一个支持延时获取元素的无界阻塞队列,使用PriorityQueue来实现
- 应用场景:
- 缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了
- 定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的
- 应用场景:
- SynchronousQueue:是一个不存储元素的阻塞队列。它支持公平访问队列,默认情况下线程采用非公平性策略访问队列。
- LinkedTransferQueue:是一个由链表结构组成的无界阻塞TransferQueue队列。
- 比其他阻塞队列多了tryTransfer和transfer方法
- 当前有消费者正在等待接收元素,transfer方法可以把生产者传入的元素立刻transfer(传输)给消费者,没有消费者在等待接收元素时,将元素存放在队列的tail节点,并等到该元素被消费者消费了才返回
- 同上,试探性是否能直接传给消费者,若无消费者,返回false。
- 比其他阻塞队列多了tryTransfer和transfer方法
- LinkedBlockingDeque:是一个由链表结构组成的双向阻塞队列