在执行者中控制任务结束

FutureTask 类提供了一个名为 done() 的方法,允许您在任务在一个执行者中执行结束后还能执行某些代码。 可被用于执行某些后处理操作、生成报表、通过邮件发送结果或释放某些资源。 当此 FutureTask 对象控制的任务结束时,done() 方法由 FutureTask 类在内部调用。 此方法在设置了任务结果、状态改变成isDone状态后被调用,不管任务是否被取消或正常结束。

默认情况此方法是空的。您可以扩展 FutureTask 类并覆盖实现 done() 方法来改变默认行为。

任务

任务结束时在终端输出任务是被取消还是正常结束的。

实现

本节的示例代码在 com.elanzone.books.noteeg.chpt4.sect10 package中

  • 执行任务线程类 : Callable<String> ExecutableTask

    • 属性 name : String 对象
    • 构造函数初始化name属性为参数值
        private String name;
    
        public ExecutableTask(String name) {
            this.name = name;
        }
    
    • call() 方法 : 随机睡上几秒后返回带有线程名称的信息
        @Override
        public String call() throws Exception {
            try {
                long duration = (long) (Math.random() * 10);
                System.out.printf("%s: Waiting %d seconds for results.\n", this.name, duration);
                TimeUnit.SECONDS.sleep(duration);
            } catch (InterruptedException e) {
            }
            return "Hello, world. I'm " + name;
        }
    
  • 结果处理线程类 : FutureTask<String> ResultTask

    • 属性 name : String 对象
    • 构造函数接受一个 Callable 对象作为参数。调用父类的构造函数并用收到的任务名称初始化name属性
        private String name;
    
        public ResultTask(Callable<String> callable) {
            super(callable);
            this.name = ((ExecutableTask) callable).getName();
        }
    
    • 覆盖 done() 方法 : 检查 isCancelled() 方法的返回值并做适当处理
        @Override
        protected void done() {
            if (isCancelled()) {
                System.out.printf("%s: Has been canceled\n", name);
            } else {
                System.out.printf("%s: Has finished\n", name);
            }
        }
    
  • 控制类 : Main

    • 使用 Executors 类的 newCachedThreadPool() 方法创建一个 ExecutorService
        ExecutorService executor = Executors.newCachedThreadPool();
    
    • 创建多个 ExecutableTask 和对应的 ResultTask , 调用 executor 的 submit() 方法送去执行
        ResultTask resultTasks[] = new ResultTask[5];
    
        for (int i = 0; i < 5; i++) {
            ExecutableTask executableTask = new ExecutableTask("Task" + i);
            resultTasks[i] = new ResultTask(executableTask);
            executor.submit(resultTasks[i]);
        }
    
    • 睡上几秒后调用 cancel() 方法取消各 ResultTask
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        for (int i = 0; i < 5; i++) {
            resultTasks[i].cancel(true);
        }
    
    • 将未被取消的任务结果信息输出到终端 使用 ResultTask 对象的 get() 方法获取信息
        for (ResultTask resultTask : resultTasks) {
            try {
                if (!resultTask.isCancelled()) {
                    System.out.printf("%s\n", resultTask.get());
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    
    • 用 shutdown() 方法停止执行
        executor.shutdown();
    

工作原理

当被控制的任务结束执行时,done() 方法被 FutureTask 类调用。 本例中实现了一个 Callable 对象(ExecutableTask 类),然后一个 FutureTask 类的子类控制此 ExecutableTask 对象的执行。

在已获得返回值并将状态改变成 isDone 状态后,done() 方法才被 FutureTask 类在内部调用。 您不能改变任务的结果值或改变它的状态,但是您可以关闭任务使用的资源、写日志信息或发送提醒。