Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制同时执行的线程数量就需要额外编写代码来完成。
5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接池的线程池来执行任务。这个架构主要有三个接口和其相应的具体类组成。这三个接口是Executor, ExecutorService和ScheduledExecutorService,让我们先用一个图来显示它们的关系:
图的左侧是接口,图的右侧是这些接口的具体类。注意Executor是没有直接具体实现的。
Executor接口:
是用来执行Runnable任务的,它只定义一个方法:
-
execute(Runnable command):执行Ruannable类型的任务
ExecutorService接口:
ExecutorService继承了Executor的方法,并提供了执行Callable任务和中止任务执行的服务,其定义的方法主要有:
-
invokeAll(collection of tasks):批处理任务集合,并返回一个代表这些任务的Future对象集合
-
submit(task):可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
-
shutdown():在完成已提交的任务后关闭服务,不再接受新任务
-
shutdownNow():停止所有正在执行的任务并关闭服务。
-
isTerminated():测试是否所有任务都执行完毕了。
-
isShutdown():测试是否该ExecutorService已被关闭
ScheduledExecutorService接口
在ExecutorService的基础上,ScheduledExecutorService提供了按时间安排执行任务的功能,它提供的方法主要有:
-
schedule(task, initDelay): 安排所提交的Callable或Runnable任务在initDelay指定的时间后执行。
-
scheduleAtFixedRate():安排所提交的Runnable任务按指定的间隔重复执行
-
scheduleWithFixedDelay():安排所提交的Runnable任务在每次执行完后,等待delay所指定的时间后重复执行。
代码:ScheduleExecutorService的例子
public class ScheduledExecutorServiceTest { public static void main(String[] args) throws InterruptedException, ExecutionException{ //*1 ScheduledExecutorService service = Executors.newScheduledThreadPool(2); //*2 Runnable task1 = new Runnable() { public void run() { System.out.println("Task repeating."); } }; //*3 final ScheduledFuture future1 = service.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS); //*4 ScheduledFuture future2 = service.schedule(new Callable(){ public String call(){ future1.cancel(true); return "task cancelled!"; } }, 5, TimeUnit.SECONDS); System.out.println(future2.get()); //*5 service.shutdown(); } } |
这个例子有两个任务,第一个任务每隔一秒打印一句“Task repeating”,第二个任务在5秒钟后取消第一个任务。
-
初始化一个 ScheduledExecutorService 对象,这个对象的线程池大小为 2 。
-
用内函数的方式定义了一个 Runnable 任务。
-
调用所定义的 ScheduledExecutorService 对象来执行任务,任务每秒执行一次。能重复执行的任务一定是 Runnable 类型。注意我们可以用 TimeUnit 来制定时间单位,这也是 Java 5.0 里新的特征, 5.0 以前的记时单位是微秒,现在可精确到奈秒。
-
调用 ScheduledExecutorService 对象来执行第二个任务,第二个任务所作的就是在 5 秒钟后取消第一个任务。
-
关闭服务。
Executors类
虽然以上提到的接口有其实现的具体类,但为了方便Java 5.0建议使用Executors的工具类来得到Executor接口的具体对象,需要注意的是Executors是一个类,不是Executor的复数形式。Executors提供了以下一些static的方法:
-
callable(Runnable task): 将Runnable的任务转化成Callable的任务
-
newSingleThreadExecutor: 产生一个ExecutorService对象,这个对象只有一个线程可用来执行任务,若任务多于一个,任务将按先后顺序执行。
-
newCachedThreadPool(): 产生一个ExecutorService对象,这个对象带有一个线程池,线程池的大小会根据需要调整,线程执行完任务后返回线程池,供执行下一次任务使用。
-
newFixedThreadPool(int poolSize):产生一个ExecutorService对象,这个对象带有一个大小为poolSize的线程池,若任务数量大于poolSize,任务会被放在一个queue里顺序执行。
-
newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,若任务多于一个,任务将按先后顺序执行。
-
newScheduledThreadPool(int poolSize): 产生一个ScheduledExecutorService对象,这个对象的线程池大小为poolSize,若任务数量大于poolSize,任务会在一个queue里等待执行
以下是得到和使用ExecutorService的例子:
代码:如何调用Executors来获得各种服务对象
//Single Threaded ExecutorService ExecutorService singleThreadeService = Executors.newSingleThreadExecutor();
//Cached ExecutorService ExecutorService cachedService = Executors.newCachedThreadPool();
//Fixed number of ExecutorService ExecutorService fixedService = Executors.newFixedThreadPool(3);
//Single ScheduledExecutorService ScheduledExecutorService singleScheduledService = Executors.newSingleThreadScheduledExecutor();
//Fixed number of ScheduledExecutorService ScheduledExecutorService fixedScheduledService = Executors.newScheduledThreadPool(3); |