Callable, Future和FutureTask简述

Posted _houzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Callable, Future和FutureTask简述相关的知识,希望对你有一定的参考价值。

JDK1.5后新增了一些接口用于并发编程的接口,Callable,Future。以及1.6添加了FutureTask。之前看到了他们的使用,JDK1.8还添加了CompletableFuture,一直想了解一下这些东西。这里记录下对Callable, Future和FutureTask的理解。

相关接口

FutureTask实现了RunnableFuture接口,而RunnableFuture继承了Runnable,Future接口。FutureTask又有一个Callable参数的构造函数,下面分别介绍这些接口。

Runnable

这个是在Java一开始就出现了的接口,只有一个接口方法run,表示可以被运行的类。可以放到线程池,Thread中运行。跟Thread是两种不同的实现方式。

Future

这是在JDK1.5新增的接口,展示异步执行的结果(结果,将来的,Future)。他有以下几个方法:

  • cancel: 尝试去取消这个任务,如果该任务已经完成,或者已经取消,或者其他什么原因将不能取消。
  • get: 可以通过get方法获取异步线程的结果,如果没有执行完成则阻塞当前线程,等待异步线程执行完获取结果。
  • isDone: 判断该任务是否已经完成。如果是被取消,中断等,该方法也会返回true。
  • isCancelled: 判断该任务是否已经取消。

Runnable和Thread都有一个问题,就是不能够直接获取异步线程运行的结果,而Future可以做到。

RunnableFuture

实现了Runnable接口和Future接口。

Callable

一个可以返回结果的接口。只有一个方法call。

使用范例

使用Callable放到线程池中运行。

public class TestFuture 
    public static void main(String[] args) throws InterruptedException, ExecutionException
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> future = executor.submit(task);
        // do something
        System.out.println("可以先做一些事情,再去获取运行结果");
        if(!future.isDone())
            // you also can do something.
        
        System.out.println("运行结果: "+future.get()); // 可能会阻塞等待结果
    

    static class Task implements Callable<Integer>

        @Override
        public Integer call() throws Exception 
            System.out.println("异步任务开始运行");
            TimeUnit.SECONDS.sleep(3);
            int sum = 0 ;
            for(int i = 0 ; i != 200; ++i)
                sum+=i;
            
            System.out.println("异步任务完成运行");
            return sum;
        

    

//运行结果
/*
可以先做一些事情,再去获取运行结果
异步任务开始运行
异步任务完成运行
运行结果: 19900
*/

可以自己实现Callable接口,Executor执行完成后会返回一个Future对象。在获取运行结果前,可以先做一些其他的事情。

使用FutureTask

public class TestFutureTask 
    public static void main(String[] args) throws InterruptedException, ExecutionException
        ExecutorService executor = Executors.newCachedThreadPool();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Task());
        executor.submit(futureTask); //调用的submit(Runnable runnable) 方法
        // do something
        System.out.println("可以先做一些事情,再去获取运行结果");
        if(!futureTask.isDone())
            // you also can do something.
        
        System.out.println("运行结果: "+futureTask.get()); // 可能会阻塞等待结果
    


    static class Task implements Callable<Integer>

        @Override
        public Integer call() throws Exception 
            System.out.println("异步任务开始运行");
            TimeUnit.SECONDS.sleep(3);
            int sum = 0 ;
            for(int i = 0 ; i != 200; ++i)
                sum+=i;
            
            System.out.println("异步任务完成运行");
            return sum;
        

    

跟前面直接使用Callable结果是一样的,只是使用方式有点不一样。这里不需要从submit中获得Future对象,直接就是传入的那个参数futureTask,在有些使用使用起来会更加方便。

总结

我觉得Future接口提供了一种异步操作新的思路,Runnable和Thread都是直接执行完就没有了,并没有获得执行结果的接口,但是Future可以获得执行结果。Future就是用来展示执行结果。当然Future这一系列接口的使用远远不止这些,Future的get方法还可以设置超时时间。

以上是关于Callable, Future和FutureTask简述的主要内容,如果未能解决你的问题,请参考以下文章

Callable和Future

Callable/Future

Callable, Runnable, Future, FutureTask

callable和runnable和future

Java线程之Callable和Future

Java - "JUC线程池" Callable与Future