天天看点

Callable 和 Runnable 的不同?Callable 和 Runnable 的不同?

Callable 和 Runnable 的不同?

文章目录

  • Callable 和 Runnable 的不同?
    • 前言
    • 项目环境
    • 1.Runnable 的缺陷
      • 1.1 没有返回值
      • 1.2 不能抛出异常
      • 1.3 设计导致
      • 1.4 Runnable 为什么设计成这样?
    • 2.Callable 接口
    • 3.Callable 和 Runnable 的不同之处
    • 4.参考

前言

本章主要是介绍 Runnable 接口和 Callable 接口的异同。

项目环境

  • jdk 1.8
  • github 地址:https://github.com/huajiexiewenfeng/java-concurrent
    • 本章模块:future

1.Runnable 的缺陷

  • @FunctionalInterface 注解是 Java 8 中和 Lambda 语法配合的一个注解

1.1 没有返回值

Runnable 接口源码如下:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
           

run 方法没有返回值,虽然有一些别的方法也能实现返回值得效果,比如编写日志文件或者修改共享变量等等,但是不仅容易出错,效率也不高。

1.2 不能抛出异常

示例:

public class RunThrowExceptionDemo {

    /**
     * 普通方法可以在方法签名中抛出异常
     *
     * @throws IOException
     */
    public void normalMethod() throws IOException {
        throw new IOException();
    }

    class RunnableImpl implements Runnable {

        /**
         * run 方法内无法抛出 checked Exception,除非使用 try catch 进行处理
         */
        @Override
        public void run() {
            try {
                throw new IOException();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
           

可以看到普通方法 normalMethod 可以在方法签名上抛出异常,这样上层接口就可以捕获这个异常进行处理,但是实现 Runnable 接口的类,run 方法无法抛出 checked Exception,只能在方法内使用 try catch 进行处理,这样上层就无法得知线程中的异常。

1.3 设计导致

其实这两个缺陷主要原因就在于 Runnable 接口设计的 run 方法,这个方法已经规定了 run() 方法的返回类型是 void,而且这个方法没有声明抛出任何异常。所以,当实现并重写这个方法时,我们既不能改返回值类型,也不能更改对于异常抛出的描述,因为在实现方法的时候,语法规定是不允许对这些内容进行修改的。

1.4 Runnable 为什么设计成这样?

假设 run() 方法可以返回返回值,或者可以抛出异常,也无济于事,因为我们并没有办法在外层捕获并处理,这是因为调用 run() 方法的类(比如 Thread 类和线程池)是 Java 直接提供的,而不是我们编写的。

所以就算它能有一个返回值,我们也很难把这个返回值利用到,而 Callable 接口就是为了解决这两个问题。

2.Callable 接口

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}
           

可以看到 Callable 和 Runnable 接口其实比较相识,都只有一个方法,也就是线程任务执行的方法,区别就是 call 方法有返回值,而且声明了 throws Exception。

3.Callable 和 Runnable 的不同之处

  • 方法名,Callable 规定的执行方法是 call(),而 Runnable 规定的执行方法是 run();
  • 返回值,Callable 的任务执行后有返回值,而 Runnable 的任务执行后是没有返回值的;
  • 抛出异常,call() 方法可抛出异常,而 run() 方法是不能抛出受检查异常的;
  • 和 Callable 配合的有一个 Future 类,通过 Future 可以了解任务执行情况,或者取消任务的执行,还可获取任务执行的结果,这些功能都是 Runnable 做不到的,Callable 的功能要比 Runnable 强大。

4.参考

  • 《Java 并发编程 78 讲》- 徐隆曦

继续阅读