Callable Future 和 FutureTask

1、基本介绍

     Runnable 是一个接口,在它里面只声明了一个 run()方法,由于 run()方法返回值为 void 类型,所以在执行完任务之后无法返回任何结果。
  Callable 位于 java.util.concurrent 包下,它也是一个接口,在它里面也只声明 了一个方法,只不过这个方法叫做 call(),这是一个泛型接口,call()函数返回的类型就是传递进来的 V 类型。
  Future 就是对于具体的 Runnable 或者 Callable 任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过 get 方法获取执行结果,该方法会阻塞直到任务返回结果。在Future类中一共有5个方法,如下图所示:

cancel(boolean mayInterruptIfRunning) 方法:尝试取消任务,如果任务已经完成、已经被取消或由于某些其他原因而无法取消,则此尝试将失败。 如果成功,并且在调用cancel()时此任务尚未开始,则该任务永远不会运行。 如果任务已经开始,则{@code mayInterruptIfRunning}参数确定是否应中断执行该任务的线程以尝试停止该任务。cancel(false)  不会中断已经运行的任务。

get() 方法:获取线程返回结果,阻塞着获取结果 
get(long timeout, TimeUnit unit) 方法:获取线程结果时设置等待时长
isCancelled() 方法:如果此任务在正常完成之前被取消,则返回true,否则返回false
isDone() 方法:如果此任务完成(无论怎么结束的,如异常结束,取消,正常结束),则返回true

由于Future 只是一个接口,无法直接用来创建对象使用,因此就有了下面的FutureTask

三者关系图如下

        如上图:FutureTask 类实现了RunnableFuture 接口,RunnableFuture 继承了Runnable接口和Future 接口。所以它既可以作为Runnable被线程执行,又可以作为Future 得到Callable 的返回值

        比如我们通过一个线程运行Callable,但是Thread 不支持构造方法中传递Callable的实例,所以我们需要通过FutureTask 把一个Callable 包装成Runnable交给Thread去运行,然后再通过这个FutureTask 拿到Callable 运行后的线程返回值。

  要new 一个FutureTask的实例,有两种方法,如下图所示。

2 代码示例

  • 类说明:Future的基本使用
package cn.lspj.ch2.future;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 类说明:Future的使用
 */
public class UseFuture {

    /**
     * 实现Callable接口,允许有返回值
     */
    private static class UseCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("Callable 子线程开始计算。。。。。。");
            int num = 0;
            for(int i=0;i<5000;i++){
                num += i;
            }
            System.out.println("Callable 线程计算结果为 num =" + num);
            return num;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        UseCallable useCallable = new UseCallable();
        // 包装callable为FutureTask
        FutureTask futureTask = new FutureTask(useCallable);
        new Thread(futureTask).start();
        System.out.println("获取子线程Callable计算返回结果:" + futureTask.get());
    }
}

执行结果

  • 类说明:Future的使用,演示在计算过程中中断任务
package cn.lspj.ch2.future;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 类说明:Future的使用,演示在计算过程中中断任务
 */
public class UseFuture {

    /**
     * 实现Callable接口,允许有返回值
     */
    private static class UseCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("Callable 子线程开始计算。。。。。。");
            int num = 0;
            for(int i=0;i<5000;i++){
                //判断线程中断标记为状态
                if(Thread.currentThread().isInterrupted()){
                    System.out.println("Callable 子线程计算任务被中断了。。。。。。。。。。");
                    return null;
                }
                Thread.sleep(1);
                num += i;
                System.out.println("num=" + num);
            }
            System.out.println("Callable 线程计算结果为 num =" + num);
            return num;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        UseCallable useCallable = new UseCallable();
        // 包装
        FutureTask futureTask = new FutureTask(useCallable);
        new Thread(futureTask).start();
        Thread.sleep(35);
        Random r = new Random(10);
        if(r.nextInt() > 5){
            System.out.println("获取子线程Callable计算返回结果:" + futureTask.get());
        } else {
            System.out.println("cancle..............");
            futureTask.cancel(true);
        }
    }
}

futureTask.cancel()  其实是改变了线程的中断位标记状态,线程的中断还是要自己实现的

执行结果

————————————————

版权声明:本文为CSDN博主「﹏半生如梦愿梦如真て」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lspj201007186/java/article/details/106247283

原文地址:https://www.cnblogs.com/hup666/p/13055990.html