Java中的Runnable、Callable和Future的关系
前提
Java中多线程包下相关的接口有Runnable
、Callable
和Future
。
Runnable
1
2
3public interface Runnable {
void run();
}Callable
1
2
3public interface Callable<V> {
V call() throws Exception;
}
Runnable和Callable的区别
Runnable
执行方法是run(),Callable
是call()Runnable
无返回值且不会抛错;Callable
带返回值且可以向外抛异常。
这两个只是个接口,并不能用来进行线程相关操作。开辟线程还是要用Thread,而Thread又只能传Runnable
,不支持传Callable
,怎么破?
解决方法:创建一个类,让他实现Runnable
接口,然后内部持有一个Callable
对象。在Runnable
的run方法中调用mCallable.call()方法。
妙啊~
这个类叫FutureTask
。
FutureTask
类图
用法
1 | Callable<String> callable = new Callable<String>() { |
Future
可以看到FutureTask
没有直接实现Runnable
,而是继承RunnableFuture
,RunnableFuture
来同时实现了Runnable和Future两个接口:
1 | public interface RunnableFuture<V> extends Runnable, Future<V> { |
且看Future
接口:
1 | public interface Future<V> { |
说明FutureTask还额外实现了Future接口的相关功能。比如说Runnable的run方法中无返回值,要取到返回值的话就要用到Future中的get方法。
到这里三者的关系应该捋清楚了。
Runnable
没返回值,Callable
有返回值,但是Thread
不接受Callable
,所以有了FutureTask
。FutureTask
实现Runnable
,传入Callable
对象。这个时候还需要写一些相关的方法(比如取出返回值的方法),然后这些方法就收录到了Future
接口中。
Future的另一个使用场景
线程池
线程池中线程来了又去,总有一个需要带返回值。
这个时候就要传入Callable了。
1 | Callable<String> callable = new Callable<String>() { |
executor.submit(callable)返回的也是一个Future
ps:其实内部调用的还是FutureTask
,submit代码如下:
1 | public <T> Future<T> submit(Callable<T> task) { |
另补充一点:FutureTask()也可以传入Runnable,不过最后还是会把Runnable转换成Callable的😂
用的这个:
1 | static final class RunnableAdapter<T> implements Callable<T> { |