在 Java 5.0 之前,启动一个任务是通过调用 Thread 类的 start() 方法来实现的,任务的提交和执行是同时进行的(任务提交之后会立即执行),如果你想对任务的执行进行调度或是控制同时执行的线程数量就需要额外编写代码来完成。
在 Java 5.0 中提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接池的线程池来执行任务。这个架构主要由三个接口和其相应的具体类组成。这三个接口是 Executor、ExecutorService 和 ScheduledExecutorService,让我们先用一个图来显示它们的关系:
图的左侧是接口,图的右侧是这些接口的具体实现类。注意 Executor 是没有直接具体实现的。
Executor 接口:
是用来执行 Runnable 任务的,它只定义一个方法:
· execute(Runnable command):执行 Ruannable 类型的任务。
ExecutorService 接口:
ExecutorService 继承了 Executor 的方法,并提供了执行 Callable 任务和中止任务执行的服务,其定义的方法主要有:
· submit():可用来提交 Callable 或 Runnable 任务,并返回代表此任务的 Future 对象;
· invokeAll():批处理任务集合,并返回一个代表这些任务的 Future 对象集合;
· shutdown():在完成已提交的任务后关闭服务,不再接受新任务;
· shutdownNow():停止所有正在执行的任务并关闭服务;
· isTerminated():测试是否所有任务都执行完毕了;
· isShutdown():测试是否该 ExecutorService 已被关闭。
ScheduledExecutorService 接口:
在 ExecutorService 的基础上,ScheduledExecutorService 提供了按时间安排执行任务的功能,它提供的方法主要有:
· scheduleschedule (Runnable command, long delay, TimeUnit unit)
· schedule (Callable<V> callable, long delay, TimeUnit unit):
安排所提交的 Runnable 或 Callable 任务在 delay 指定的时间后执行;
· scheduleAtFixedRate (Runnable command, long initialDelay, long period, TimeUnit unit):
安排所提交的 Runnable 任务按指定的间隔重复执行;
· scheduleWithFixedDelay (Runnable command, long initialDelay, long delay, TimeUnit unit):
安排所提交的 Runnable 任务在每次执行完后,等待delay所指定的时间后重复执行。
虽然以上提到的接口都有其实现的具体类,但为了方便,Java 5.0 建议使用 Executors 的工具类来得到实现 Executor 接口的具体对象,需要注意的是 Executors 是一个类,不是 Executor 的复数形式。
Executors 类
Executors 类主要定义了一些工厂方法和工具方法,其中最重要的就是创建各种线程池:
· public static ExecutorService newFixedThreadPool (int nThreads):
创建一个可重用、固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
(创建固定数目线程的线程池,返回一个 ExecutorService 对象,这个对象带有一个大小为 nThreads 的线程池,若任务数量大于 nThreads,任务会被放在一个 Queue 里顺序执行)
· public static ExecutorService newCachedThreadPool():
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
(返回一个 ExecutorService 对象,这个对象带有一个线程池,线程池的大小会根据需要进行调整,线程执行完任务后返回线程池,供执行下一次任务使用。)
· public static ExecutorService newSingleThreadExecutor():
创建一个单线程化的 ExecutorService ;
返回一个 ExecutorService 对象,这个对象的线程池大小为 1,若任务多于一个,任务将按先后顺序执行。
· public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize):
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
(创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代 Timer 类;返回一个 ScheduledExecutorService 对象,这个对象的线程池大小为 corePoolSize,若任务数量大于 corePoolSize,任务会在一个 Queue里 等待执行。)
· public static ThreadFactory defaultThreadFactory():
返回用于创建新线程的默认线程工厂。此工厂创建同一个线程组(ThreadGroup)中 Executor 使用的所有新线程。如果有 SecurityManager,则它使用 System.getSecurityManager()返回的组,其他情况则使用调用 defaultThreadFactory 方法的组。每个新线程都作为非守护程序而创建,并且具有设置线程优先级为 Thread.NORM_PRIORITY 与线程组中允许的最大优先级的较小者。新线程具有可通过 pool-N-thread-M 的 Thread.getName() 来访问的名称,其中 N 是此工厂的序列号,M 是此工厂所创建线程的序列号。
· void execute(Runnable command):
在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。
· void shutdown():
启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
参考资料:
http://jiajun.iteye.com/blog/453544
http://www.iteye.com/topic/366591