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 讲》- 徐隆曦