Callable和Runnable
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
Callable和Runnable是两个功能十分相近的功能。Callable是Runnable的扩展,Runnable是Callable的基础。从两个接口的代码来看,它们主要有以下区别:
- call能抛出受检查的异常,而run方法不能。
- call能返回一个值,而run不能。
如果想要获取到run方法的执行结果,那我们不得不在run方法中增加将结果放入公共对象的代码
疑问:
创建线程最根本的一个要求就是重写Runnable方法。Callable和Runnable接口并没有实现或被实现关系,Callable是如何被创建为一个新线程的?
创建线程最根本的要求是重写Runnable方法,这是绕不开的。在FutureTask中,我们常常使用构造函数FutureTask(Callable callable)实现依赖注入。而我们再查看run方法,会发现run方法调用了callable.call,从而实现了对callable的封装
虽然可以通过泛型指定get的返回类型,但是异常就没有那么幸运了。并没有一种机制可以像泛型一样使得get精准的抛出call所抛出的异常。无论call抛出什么异常,最终都会被封装为ExecutionException并在get被调用时抛出。这将使调用get方法的代码变得复杂,因为它不仅需要处理可能出现的ExecutionException,而且还由于ExecutionException是作为一个Throwable类返回的,因此处理起来并不容易