Skip to content
DAILY QUOTE

“ ”

Callable

Callable和Runnable对比

Callable表示有返回值的任务,Runnable表示没有返回值的任务。Thread构造方法只能直接接收Runnable,所以Callable通常需要先包装成FutureTask,再交给Thread执行。

  • Callablejava.util.concurrent包下的接口,有返回值,可以抛出被检查异常。
  • Runnablejava.lang包下的接口,没有返回值,不能直接抛出被检查异常。
  • 二者调用的方法不同:Runnable执行run()Callable执行call()

FutureTask实现了RunnableFuture接口,而RunnableFuture又继承了Runnable,所以Thread可以接收FutureTask对象。

java
new Thread(new Runnable()).start();  //创建一个线程去执行一个没有返回值的任务。
new Thread(new FutureTask<V>()).start(); //FutureTask实现了RunnableFuture接口,而RunnableFuture又继承了Runnable。所以Thread觉得它是Runnable,就接收了它。
new Thread(new FutureTask<V>(Callable)).start();

代码测试

java
package com.mystpet.Callable;  
  
import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.FutureTask;  
  
public class CallableTest {  
    public static void main(String[] args) throws ExecutionException, InterruptedException {  
        MyThread thread = new MyThread();  
        FutureTask<Integer> futureTask = new FutureTask<>(thread);  
  
        new Thread(futureTask,"A").start();  
        new Thread(futureTask,"B").start();  
  
        Integer integer=futureTask.get();  
  
        System.out.println(integer);  
  
    }  
}  
class MyThread implements Callable<Integer> {  
  
    @Override  
    public Integer call() throws Exception {  
        System.out.println("call");  
        return 1024;  
    }  
}

运行结果:

A与B共用的是同一个futureTask对象

  • 缓存机制FutureTask内部维护了一个state(状态机)。

  • 只执行一次:当线程A拿到futureTask并成功调用了call()方法后,FutureTask会将状态从NEW更新为COMPLETING,最后变为NORMAL(完成)。

  • 结果复用:当线程B启动时,它会检查futureTask的状态。发现任务已经执行过或正在执行,它就不会再重复调用call()方法,而是直接等待结果。

细节

1、有缓存

2、结果可能需要等待,会阻塞!