菜鸟谈——Callable和Future
1. 是什么
Callable接口类似于Runnable。但是Runnable不会返回结果,并且无法抛出异常,而Callable功能更加强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,即Future可以拿到异步执行任务的返回值。。
代码样例如下:
package cn.km.callableAndFuture;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class test {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start(); //开启线程执行
try {
Thread.sleep(500); //do something
System.out.println(futureTask.get()); //获取返回的结果值
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 原理
FutureTask实现了两个接口Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。。。
假设有个很耗时的返回值没有计算,并且这个返回值不是立刻需要的话,那么可以使用另外一个线程去计算返回值,而当当前线程在使用这个返回值之前可以做其他的操作,等到需要这个返回值时,再通过Future获取。
2.1 Future接口类解析
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
解析每个方法的作用:
cancel方法:用来取消任务,如果取消成功则返回true,如果取消任务失败则返回false。
参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。
如果任务已经完成,无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即取消已经完成的任务cancel()则会返回false。
如果任务正在执行,若mayInterruptIfRunning设置为true,则cancel()函数返回true;若mayInterruptIfRunning设置为false,则cancel()函数返回false。
如果任务还没有执行,无论mayInterruptIfRunning设置为true或者false,肯定返回true。
isCancelled()方法:任务是否被取消成功,如果在任务正常完成前被取消成功,则返回true。
isDone()方法:任务是否已经完成,若任务完成则返回true。
get()方法:用来获取执行结果,这个方法会产生阻塞,会一直等待任务执行完成才返回。
get(long timeout,TimeUnit unit)方法:用来获取执行结果,如果在指定的时间范围内,还没有获取到结果,就直接返回null。
**总结:**Future提供了三种功能:1)判断任务是否完成;2)能够中断任务;3)能够获取任务执行结果。
2.2 FutureTask类解析
FutureTask的实现
public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture的实现
public interface RunnableFuture<V> extends Runnable, Future<V>
由上可知,FutureTask既可以作为Runnable被线程调用,又可以作为Future得到callable的返回值。
FutureTask构造函数
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}