Callable和Runnable

113 阅读2分钟

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的基础。从两个接口的代码来看,它们主要有以下区别:

  1. call能抛出受检查的异常,而run方法不能。
  2. 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类返回的,因此处理起来并不容易