一、为什么要使用executor
对于简单的任务来说,通常只需要将所需要完成的任务写在runnable中,并构造一个Thread即可。但是对于更大型、更复杂的应用,有必要将线程的创建和管理(creation and management)单独拎出来。executor是一个接口,它的实现类封装了这些功能,线程池是最常见的executor的实现。
java提供了以下三个接口:
Executor
ExecutorService
Executor
的子接口,支持处理所需执行的任务以及executor本身的生命周期。ScheduledExecutorService
ExecutorService
的子接口,支持在任务的预后/间断执行。
executor简化了线程的创建和使用,比如通常的传入一个Runnable构造Thread并让其运行:
(new Thread(r)).start();
e.execute(r);
根据Executor的实现,execute方法可能也只是像显示使用Thread类那样,创建线程并立即启动;但更多情况下,会使用一个存在的工作线程去运行runnable或者将runnable放置在一个队列中等待工作线程可用。ExecutorService以及
ScheduledExecutorService
的在Executor接口的基础上提供了更多功能。
二、线程池(ThreadPool)
绝大多数executor的实现都使用了包含工作线程的线程池,这种线程相对于其所执行的Runnable
和 Callable
是独立存在的。工作线程常被用于处理复杂的任务。
在大型应用里线程调度需要大量的内存管理工作,而使用工作线程省去了创建线程的麻烦。
fixed thread pool制定了运行的线程的数目—当一个线程在使用过程中被终止,会自动被一个新的线程所取代。任务经由一个内部队列传递到线程池,该内部队列存放着额外的任务(当任务数多于线程池规定的线程数)。
线程池的好处是能够让任务有序地被处理,而不会出现因为任务过多导致新线程不断地被创建导致资源耗竭。创建一个fixed thread pool使用java.util.concurrent.Executors
中的newFixedThreadPool
工厂方法即可。
还有其他的方法:
- The
newCachedThreadPool
创建一个线程池可以扩展的executor,适用于任务运行时间短、数目多的应用。 - The
newSingleThreadExecutor
创建一个每次只有一个任务被执行的executor。 - 在
ScheduledExecutorService
类中有上述个方法的相应的工厂方法。