搞懂 Runnable、Future、Callable、FutureTask 之间的关系,这篇就够了

前言

创建线程的两种方式主要有继承 Thread 类 或 实现 Runnable 接口,重写 run 方法,无论我们使用 Thread 还是 Runnable 新建线程,它都无法返回结果值。自从 Jdk1.5 开始,官方提供了 Callable 和 Future, 通过他们就可以获得任务的执行结果。其中 FutureTask 则作为 Future 的实现类。

下面是他们的关系类图:

在这里插入图片描述

Runnable

Thread 类本身也实现了 Runnable 接口,Runnable 接口源码如下:

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

因此,可以看得出,不管我们是实现 Runnable 接口,还是继承 Thread 类,run 方式的返回类型都是 void,,没有任务返回接口,并且无法抛出异常。

如果需要获取任务返回结果怎么办?Callable 便应运而生了。

Callable

Callable 是一个接口,一个函数式接口,也是一个泛型接口,只有一个 call 方法,在 call 方法里面编写我们要执行的代码就行了。返回的就是执行的结果。Callable 可以看作是 Runnable 接口的补充,和 Runnable 的区别就是它有返回任务结果,并且可以抛出异常,一般配合 ThreadPoolExecutor 使用。

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Future

Future 是个接口,它可以对具体的 Runnable 或者 Callable 任务进行取消、判断任务是否已取消、查询任务是否完成、获取任务结果。接口里面有以下几个方法。注意两个 get 方法都会阻塞当前调用 get 的线程,直到返回结果或者超时才会唤醒当前的线程。

public interface Future<V> {
 
    //取消任务的执行,任务已经完成或者已经被取消时,调用此方法,会返回false
    boolean cancel(boolean mayInterruptIfRunning);
 
    //判断任务是否被取消
    boolean isCancelled();
 
    //判断任务是否完成(正常完成、异常以及被取消,都将返回true)
    boolean isDone();
 
    //阻塞地获取任务执行的结果
    V get() throws InterruptedException, ExecutionException;
 
    //在一定时间内,阻塞地获取任务执行的结果
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
 
}

但由于 Future 只是一个接口,为了使用它里面的功能,我们必须使用它的间接继承类 FutureTask。

FutureTask

FutureTask 是真正工作的处理类,FutureTask 实现了 RunnableFuture 接口,而 RunnableFuture 继承了 Runnable 与 Future 接口,因此 FutureTask 既可以作为一个Runnable 被 Thread 执行,也可以获取到 Future 异步计算的结果。

在这里插入图片描述

在这里插入图片描述

它的两个构造器:

    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Callable}.
     *
     * @param  callable the callable task
     * @throws NullPointerException if the callable is null
     */
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Runnable}, and arrange that {@code get} will return the
     * given result on successful completion.
     *
     * @param runnable the runnable task
     * @param result the result to return on successful completion. If
     * you don't need a particular result, consider using
     * constructions of the form:
     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
     * @throws NullPointerException if the runnable is null
     */
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

两个构造方法,一个接收 Callable 的参数实例,另一个接收 Runnable 的参数实例。

当传入的参数是 Runnable 时,通过 Executors.callable(runnable, result) 方法将其转成 Callable 类型,返回值类型为 V(指定的泛型类型)

FutureTask 代码案例

public class Test {
	
    static class MyTask implements Callable<Integer> {
    	@Override
        public Integer call() throws Exception {
            Thread.sleep(2000);
            return 1;


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

        ExecutorService executor = Executors.newCachedThreadPool();
        MyTask myTask = new MyTask();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(myTask);
        executor.submit(futureTask);
        executor.shutdown();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("主线程在执行任务");
         
        try {
            if(futureTask.get()!=null){  
                System.out.println("task运行结果"+futureTask.get());
            }else{
                System.out.println("future.get()未获取到结果"); 
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("所有任务执行完毕");
    }

}
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值