并发编程学习笔记(15)----Executor框架的使用
Executor执行已提交的 Runnable
任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用 Executor 而不是显式地创建线程。例如,可能会使用以下方法,而不是为一组任务中的每个任务调用 new Thread(new(RunnableTask())).start():
实例化Executor对象时,通常使用Executors中的静态方法返回Executor的子接口ExecutorService;这里主要介绍Executors中几个静态方法创建的线程池的作用
1)newCachedThreadPool() :创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们;我们来看它的实现:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
其实都是使用前面锁介绍的ThreadPoolExecutor类来创建线程池,不过这里改变了传入的参数使其拥有了不同的用法,corePoolSize为0,无限大个最大线程数,最大存活时间为60s,使用SynchronousQueue这种没有容量的队列,就相当于将创建的线程缓存起来,在提交任务的时候可以无限的创建线程来指示,当池中线程个数空闲时间超过60s时就销毁线程,达到了缓存的效果。
2) newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地 关闭
之前,池中的线程将一直存在。
3) newScheduledThreadPool(int corePoolSize: 创建一个可执行计划任务的线程池,它可安排在给定延迟后运行命令或者定期地执行。
4)newSingleThreadExecutor() 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,当当前线程意外死掉时会创建新的线程继续执行任务。
Executors中还有很多创建线程的方式,与以上四个大同小异,这里就不在详述,值得一说的是,所有方法都重载了可以指定ThreadFactory的方法。
创建线程池之后,还需要像线程池提交任务,这里来看两种任务提交方法。
execute():接收Runnable,它属于在Executor接口中定义的方法,无返回值的任务提交。
submit(): 接收Callable/Runnable/Runnable和返回值T,它属于ExecutorService接口中定一的三个重载方法,用于有返回值的任务的提交。
线程池的关闭的两个方法
shutdown(): 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
shutdownNow(): 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。例如,通过 Thread.interrupt()
来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止。