声明:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González 译者:许巧辉 校对:方腾飞,叶磊
执行者控制一个任务完成
FutureTask类提供一个done()方法,允许你在执行者执行任务完成后执行一些代码。你可以用来做一些后处理操作,生成一个报告,通过e-mail发送结果,或释放一些资源。当执行的任务由FutureTask来控制完成,FutureTask会内部调用这个方法。这个方法在任务的结果设置和它的状态变成isDone状态之后被调用,不管任务是否已经被取消或正常完成。
默认情况下,这个方法是空的。你可以重写FutureTask类实现这个方法来改变这种行为。在这个指南中,你将学习如何重写这个方法,在任务完成之后执行代码。
准备工作…
这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。
如何做…
按以下步骤来实现的这个例子:
1.创建ExecutableTask类,并指定其实现Callable接口,参数化为String类型。
1 |
public class ExecutableTask implements Callable<String> { |
2.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。实现getName()方法,返回这个属性值。
2 |
public String getName(){ |
3.实现这个类的构造器,初始化任务的名称。
1 |
public ExecutableTask(String name){ |
4.实现call()方法。使这个任务睡眠一个随机时间,返回任务名称的信息。
02 |
public String call() throws Exception { |
04 |
long duration=( long )(Math.random()* 10 ); |
05 |
System.out.printf("%s: Waiting %d seconds for results.\ |
06 |
n", this .name,duration); |
07 |
TimeUnit.SECONDS.sleep(duration); |
08 |
} catch (InterruptedException e) { |
10 |
return "Hello, world. I'm " +name; |
5.实现ResultTask类,继承FutureTask类,参数化为String类型。
1 |
public class ResultTask extends FutureTask<String> { |
6.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。
7.实现这个类的构造器。它接收一个Callable对象参数。调用父类构造器,使用接收到的任务的属性初始化name属性。
1 |
public ResultTask(Callable<String> callable) { |
3 |
this .name=((ExecutableTask)callable).getName(); |
8.重写done()方法。检查isCancelled()方法返回值,并根据这个返回值的不同,写入不同的信息到控制台。
2 |
protected void done() { |
4 |
System.out.printf( "%s: Has been canceled\n" ,name); |
6 |
System.out.printf( "%s: Has finished\n" ,name); |
9.实现示例的主类,创建Main类,实现main()方法。
2 |
public static void main(String[] args) { |
10.使用Executors类的newCachedThreadPool()方法创建ExecutorService。
1 |
ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool(); |
11.创建存储5个ResultTask对象的一个数组。
1 |
ResultTask resultTasks[]= new ResultTask[ 5 ]; |
12.初始化ResultTask对象。对于数据的每个位置,首先,你必须创建ExecutorTask,然后,ResultTask使用这个对象,然后,然后submit()方法提交ResultTask给执行者。
1 |
for ( int i= 0 ; i< 5 ; i++) { |
2 |
ExecutableTask executableTask= new ExecutableTask( "Task " +i); |
3 |
resultTasks[i]= new ResultTask(executableTask); |
4 |
executor.submit(resultTasks[i]); |
13.令主线程睡眠5秒。
2 |
TimeUnit.SECONDS.sleep( 5 ); |
3 |
} catch (InterruptedException e1) { |
14.取消你提交给执行者的所有任务。
1 |
for ( int i= 0 ; i<resultTasks.length; i++) { |
2 |
resultTasks[i].cancel( true ); |
15.将没有被使用ResultTask对象的get()方法取消的任务的结果写入到控制台。
01 |
for ( int i= 0 ; i<resultTasks.length; i++) { |
03 |
if (!resultTasks[i].isCanceled()){ |
04 |
System.out.printf( "%s\n" ,resultTasks[i].get()); |
06 |
} catch (InterruptedException | ExecutionException e) { |
16.使用shutdown()方法关闭执行者。
它是如何工作的…
当控制任务执行完成后,FutureTask类调用done()方法。在这个示例中,你已经实现一个Callable对象,ExecutableTask类,然后一个FutureTask类的子类用来控制ExecutableTask对象的执行。
在建立返回值和改变任务的状态为isDone状态后,done()方法被FutureTask类内部调用。你不能改变任务的结果值和它的状态,但你可以关闭任务使用的资源,写日志消息,或发送通知。
参见