Java多线程——Callable、Future和FutureTask

通过Thread或Runnable创建的线程,都需要重写run方法,而run方法的返回是void的,所以使用这种方式无法获取线程执行结果。但java提供了其他类和方法来获取线程执行结果,主要的类有Callable、Future和FutureTask。

Callable

Callable是个泛型接口 Callable ,该接口中只有个call()方法,并且返回值也为 V,常和ExecutorService中的 submit 方法配合使用。

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

Future

Future可以对具体的 Runnable 或者 Callable 任务的执行结果进行取消、查询是否完成、获取结果等操作。可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Future 接口中有5个方法:

cancel()方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false;

isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true;

isDone方法表示任务是否已经完成,若任务完成,则返回true;

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

FutureTask

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

FutureTask提供了2个构造器:

public FutureTask(Callable<V> callable) {
}

所以实现了Callable的对象可以通过该构造器得到一个FutureTask,而FutureTask可以直接给线程来执行,然后通过FutureTask取回执行结果。

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

可以看出该构造器通过 Executors.callable() 把Runnable转换为Callable,其内部使用了适配器 RunnableAdapter。因此FutureTask实现了Future、Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。

示例代码

ExecutorService的两个方法:

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);

可以看出,通过第一个方法直接执行Callable,然后从Future中获取结果;或者用 FutureTask(Callable callable) 构造个FutureTask(它实现了Runable接口)对象用第二个方法获取返回结果,或者直接就在一个线程中执行。

代码实现:

public class ThreadCallablePractice {

    public void callableTest() throws Exception{

        ExecutorService executorService = Executors.newFixedThreadPool(3);
        Future<String> future = executorService.submit(new Task());
        executorService.shutdown();
        System.out.println(future.get());
    }

    public void futureTaskTest() throws Exception{
        FutureTask<String> futureTask = new FutureTask<String>(new Task());
        //new Thread(futureTask).start();
        //或者仍用线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(futureTask);
        executorService.shutdown();
        System.out.println(futureTask.get());
    }

    public static void main(String[] args) throws Exception{
        ThreadCallablePractice practice = new ThreadCallablePractice();
        //practice.callableTest();
        practice.futureTaskTest();

    }
}

class Task implements Callable<String>{

    public String call(){
        System.out.println(Thread.currentThread().getName() + " is working");
        return "callable result";
    }
}

运行结果

pool-1-thread-1 is working
callable result

参考资料

Java并发编程:Callable、Future和FutureTask
Callable和Future、FutureTask的使用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值