线程执行者(十)执行者控制一个任务完成

本文介绍如何利用FutureTask类的done()方法,在任务完成后执行特定代码,包括资源释放、日志记录等。通过示例代码展示了如何创建自定义FutureTask子类ResultTask,以及如何重写done()方法。

执行者控制一个任务完成

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()方法,返回这个属性值。


1 private String name;
2 public String getName(){
3 return name;
4}

3.实现这个类的构造器,初始化任务的名称。


1 public ExecutableTask(String name){
2 this.name=name;
3}

4.实现call()方法。使这个任务睡眠一个随机时间,返回任务名称的信息。


01@Override
02 public String call() throws Exception {
03 try {
04 long duration=(long)(Math.random()*10);
05 System.out.printf("%s: Waiting %d seconds for results.\
06 n",this.name,duration);
07TimeUnit.SECONDS.sleep(duration);
08 } catch (InterruptedException e) {
09}
10 return "Hello, world. I'm "+name;
11}

5.实现ResultTask类,继承FutureTask类,参数化为String类型。


1 public class ResultTask extends FutureTask<String> {

6.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。


1 private String name;

7.实现这个类的构造器。它接收一个Callable对象参数。调用父类构造器,使用接收到的任务的属性初始化name属性。


1 public ResultTask(Callable<String> callable) {
2 super(callable);
3 this.name=((ExecutableTask)callable).getName();
4}

8.重写done()方法。检查isCancelled()方法返回值,并根据这个返回值的不同,写入不同的信息到控制台。


1@Override
2 protected void done() {
3 if (isCancelled()) {
4 System.out.printf("%s: Has been canceled\n",name);
5 } else {
6 System.out.printf("%s: Has finished\n",name);
7}
8}

9.实现示例的主类,创建Main类,实现main()方法。


1 public class Main {
2 public static void main(String[] args) {

10.使用Executors类的newCachedThreadPool()方法创建ExecutorService。


1ExecutorService 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);
4executor.submit(resultTasks[i]);
5}

13.令主线程睡眠5秒。


1 try {
2 TimeUnit.SECONDS.sleep(5);
3 } catch (InterruptedException e1) {
4e1.printStackTrace();
5}

14.取消你提交给执行者的所有任务。


1 for (int i=0; i<resultTasks.length; i++) {
2 resultTasks[i].cancel(true);
3}

15.将没有被使用ResultTask对象的get()方法取消的任务的结果写入到控制台。


01 for (int i=0; i<resultTasks.length; i++) {
02 try {
03 if (!resultTasks[i].isCanceled()){
04 System.out.printf("%s\n",resultTasks[i].get());
05}
06 } catch (InterruptedException | ExecutionException e) {
07e.printStackTrace();
08}
09 
10}

16.使用shutdown()方法关闭执行者。


1executor.shutdown();
2}
3}

它是如何工作的…

当控制任务执行完成后,FutureTask类调用done()方法。在这个示例中,你已经实现一个Callable对象,ExecutableTask类,然后一个FutureTask类的子类用来控制ExecutableTask对象的执行。

在建立返回值和改变任务的状态为isDone状态后,done()方法被FutureTask类内部调用。你不能改变任务的结果值和它的状态,但你可以关闭任务使用的资源,写日志消息,或发送通知。

参见

  • 在第4章,线程执行者中的执行者执行返回结果的任务指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值