Executor
线程池框架Executor
概述
Executor是(since)JDK1.5实现的线程池技术,先看Executor框架的主要类与接口
Executor主要可以分为3个部分:
任务对象的创建
:实现
Runnable
接口或实现Callable
接口任务的执行
:接口ExecutorService、两个实现类
ThreadPoolExecutor
和ScheduledThreadPoolExecutor
异步计算的结果
:接口Future以及实现类FutureTask
任务对象
通过两种方式创建任务对象:实现Runnable
接口或实现Callable
接口。
Runnable不会返回结果,Callable可以返回结果;
Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常
可以通过Executors工具类提供的两个方法将Runnable包装为Callable:
任务执行
任务的执行是由两个实现类完成的:ThreadPoolExecutor
和ScheduledThreadPoolExecutor
。
前面介绍线程池工作过程就是以ThreadPoolExecutor
为例进行的。在实际使用中,通常使用工具类Executors
创建不同类型的
ThreadPoolExecutor
。而ScheduledThreadPoolExecutor
是ThreadPoolExecutor
类的子类,相当于特定功能的扩展:在给定的延迟之后运行任务或者定期执行任务。它与Timer的功能类似,但更强大、更灵活。Timer对应的是单个后台线程,而
ScheduledThreadPoolExecutor
可以指定多个线程数。
ThreadPoolExecutor
工具类Executors
可以创建3中类型的ThreadPoolExecutor
,分别如下。
(1)FixedThreadPool:可重用、固定线程数的线程池
可以看出,①FixedThreadPool的corePoolSize和maxmumPoolSize都被设置为nThreads;②keepAliveTime设为0,表示某工作线程一旦空闲,就立即关闭该工作线程。③使用无界队列LinkedBlockingQueue,当线程池中的线程数达到corePoolSize后,新任务将会在无界队列中等待,因此线程数永远不会超过corePoolSize。FixedThreadPool适用于为了满足资源管理的需求,而需要限制当前线程数量的场景,比如负载较重的服务器。
(2)SingleThreadExecutor
参数与FixedThreadPool的区别仅在于corePoolSize和maxmumPoolSize均为1,keepAliveTime和使用的阻塞队列都一样,特性类似,可以概括为:当有新任务时,如果线程池中没有线程,则创建一个线程,之后来的任务都存储在无界队列LinkedBlockingQueue中。该线程一直从队列中取任务执行。假如任务都执行完毕,立即终止该线程。SingleThreadExecutor适用于需要保证顺序地执行各个任务,并且在任意时间点,不会有多个线程是活动的场景。
(3)CachedThreadPool:根据需要创建新的线程
①使用无容量队列SynchronousQueue,但maxmumPoolSize无界。如果提交任务的速度大于线程处理任务的速度,将会不断创建新线程,极端情况会因为创建过多线程而耗尽CPU资源。 ②keepAliveTime为60s,空闲线程超过该时间将会终止。 ③执行完任务的某线程会执行SynchronousQueue.poll()从队列中取任务,这个取的动作会持续60s,如果在60s内有新的任务,则执行新的任务,没有任务则终止线程。因此长时间保持空闲的CachedThreadPool不会占用任何资源。 ④当有任务提交时,a.如果当前线程池为空或者已创建的线程都正在处理任务,则CachedThreadPool会创建新线程来执行该任务。b.如果当前线程池有空闲的线程(正在执行阻塞方法SynchronousQueue.poll()),则将任务交给该等待任务的空闲线程来执行。CachedThreadPool适用于执行很多的短期异步任务的小程序或者是负载较轻的服务器。
ScheduledThreadPoolEecutor
用来执行定期任务或者在给定延迟时间之后执行任务。TODO
获取异步结果
主要是通过接口Future和实现类FutureTask。
Future
Future代表了一个异步计算的结果。
JDK文档上给出的示例
FutureTask
FutureTask就像它的名字一样,既有Future的特点(实现Future接口),又具有任务的特点(实现Runnable接口)。更直白的理解是,FutureTask就是一种特殊的任务的描述类,利用FutureTask创建的任务可以获取计算结果。
FutureTask表示一个可取消的异步计算,并通过实现Future接口来开始或取消一个计算、查看计算是否完成、获取计算结果。如果计算还没有完成,调用FutureTask的get方法会阻塞当前线程(调用get方法所在的线程)。
FutureTask可以用来包装Callable和Runnable对象,因为实现了Runnable接口,所以FutureTask可以提交给Executor来执行(不提交就调用自己的run方法,也可以执行计算)。
作为一个独立的类,该类提供了很多protected的方法,以便创建你自己的定制任务类。
内容来源
大多数摘抄自《Java并发编程的艺术》
Last updated