我已经理解了Java中Runnable
和Callable
接口之间的区别。从Java 1.5到Runnable
接口已添加了其他功能,并且为了保持向后兼容性而被称为Callable
。
我现在的问题是我们有Callable
界面,我们是否总是使用它?不使用Callable
和使用Runnable
的用例有哪些?
(This是关于它们之间有什么区别的好文章)
答案 0 :(得分:33)
两者都有它们的用途,并且java.util.concurrent中的Executor框架都支持它们。 Runnable已经存在了很长时间,但它仍然在使用而不是气馁。
Callables可以抛出异常并返回值,这使得它们成为结果承载任务的更好抽象(例如从网络获取资源,执行昂贵的值计算等)[来自 Java Goetz,Bloch等人的“实践中的并发”。 al。,关于Java并发的标准工作]。
因此,如果您正在设计API,我建议尽可能使用Callables。如果您确定任务不会返回值并且不会抛出异常,那么Runnables也是一个有效的选择。这里没有黑色和白色,特别是因为Runnables可以很容易地用Callables包裹,反之亦然。
另外,请注意您的Callable实现不需要声明throws Exception
; Callable本身声明它只是允许实现者抛出任何已检查的异常。但是,仅依赖于Callable接口的Callable的调用者必须编写异常处理代码
另请注意,Callables不需要返回值;您只需声明您的Callable返回Void
(使用大写“V
”)。
答案 1 :(得分:8)
恕我直言,Runnable是一个更好的类型,在将参数作为参数时使用
不要忘记Callable.call()
抛出异常。这意味着如果你将Callable作为参数,这个Callable可以抛出任何类型的异常,你必须有一种方法以正确的方式处理它们。如果你不能这样做,最好让Callable的实现者按照自己的意愿处理异常,并使参数成为Runnable以使其清晰。
答案 2 :(得分:7)
不使用Callable
的情况:ScheduledExecutorService.scheduleAtFixedRate
和scheduleWithFixedDelay
仅接受Runnable
。
答案 3 :(得分:6)
我更喜欢Callable
,但在极少数情况下,您可能需要Callable
为Runnable
,您可以通过添加run()
这样的方法轻松实现这两种方法到你的Callable
。
public void run(){
try{
call();
} catch (Exception e){
e.printStackTrace(); // or however you log errors
}
}
在Java 8中,您还可以创建一个界面来为您执行相同的操作:
public interface CallableRunnable<T> extends Callable<T>, Runnable {
default void run(){
try {
call();
} catch (Exception e) {
e.printStackTrace(); // or however you log errors
}
}
}
然后你只需要将implements Callable<T>
更改为implements CallableRunnable<T>
。这样,任何一种方法都可以调用你的工作。当然,如果您需要特定的错误处理,您仍然可以覆盖run()方法来处理call()
方法抛出的异常。您甚至可以实现一种方法:
public interface CallableRunnable<T> extends Callable<T>, Runnable {
default void run(){
try {
call();
} catch (Exception e) {
handleCallExceptions(e);
}
}
default void handleCallExceptions(Exception e){
e.printStackTrace();
}
}
然后,任何特殊的异常处理只需要实现自己的handleExceptions(Exception)
方法......但如果你不需要,则不需要。我更喜欢这个,因为它允许你有一个使用你的日志框架等的实现。
答案 4 :(得分:0)
Callable和 Runnable 彼此相似,可用于实现线程。如果要实现 Runnable ,则必须实现 run()方法,但如果是可调用的,则必须实现 call()方法,这两种方法以类似的方式工作,但可调用的 call()方法具有更大的灵活性。两者之间存在一些差异。
可运行和可调用之间的区别如下-
1)可运行的 run()方法返回 void ,这意味着如果您希望线程返回一些可以进一步使用的东西,您无法选择Runnable run()方法。有一个解决方案'Callable',如果您想以 object 的形式返回任何东西,则应使用Callable而不是Runnable 。可调用接口具有方法'call()',该方法返回Object 。
方法签名- 可运行的->
public void run(){}
Callable->
public Object call(){}
2)如果使用 Runnable run()方法,如果出现任何已检查的异常,则必须使用try catch块进行处理,但是如果使用您可以引发以下检查异常的可调用call()方法,如下所示
public Object call() throws Exception {}
3)可运行来自旧版 java 1.0 版本,而可调用来自 Java 1.5 版本,其中< strong>执行者框架。
如果您熟悉执行者,则应该使用Callable而不是Runnable 。
希望您能理解