38

我已经了解Java中Runnable和接口之间的区别。Callable从 Java 1.5 开始,额外的特性被添加到Runnable接口并被调用Callable以保持向后兼容性。

我的问题是现在我们有了Callable接口,我们应该一直使用它吗?不使用Callable和使用的用例是Runnable什么?

是一篇关于它们之间有什么区别的好文章)

4

5 回答 5

34

两者都有各自的用途,并且都由 java.util.concurrent 中的 Executor 框架支持。Runnable 已经存在了更长的时间,但它仍在使用中并且不气馁。

Callables 可以抛出异常并返回值,这使得它们成为结果承载任务(例如从网络获取资源、执行昂贵的值计算等)的更好抽象 [来自Goetz的Java Concurrency in Practice ,布洛赫等。al.,Java 并发的标准工作]。

所以,如果你正在设计一个 API,我建议尽可能使用 Callables。如果您确定任务不会返回值并且不会抛出异常,那么 Runnables 也是一个有效的选择。这里没有黑白之分,特别是因为 Runnables 可以很容易地包裹在 Callables 中,反之亦然。

顺便说一句,请注意您的 Callable 实现不需要声明throws Exception; 事实上,Callable 本身声明它只是为了允许实现者抛出任何已检查的异常。但是,仅依赖 Callable 接口的 Callable 调用者将不得不编写异常处理代码。
另请注意,Callables 不需要返回值;您可以简单地声明您的 Callable 返回Void(使用大写“ V”)。

于 2013-05-26T12:39:56.310 回答
8

恕我直言,当将函数作为参数时,Runnable 是一种更好的类型

  • 没有返回值,只有副作用
  • 必须处理异常,而不是传播它们

不要忘记Callable.call()抛出异常。这意味着如果您将 Callable 作为参数,则此 Callable 可以抛出任何类型的异常,并且您必须有一种方法以正确的方式处理它们。如果你不能这样做,最好让 Callable 的实现者按照他的意愿处理异常,并将参数设置为 Runnable 以明确这一点。

于 2013-05-26T08:01:06.310 回答
7

不使用的用例CallableScheduledExecutorService.scheduleAtFixedRate并且scheduleWithFixedDelay只接受Runnable

于 2013-05-26T07:57:40.247 回答
6

我更喜欢Callables,但在极少数情况下您可能需要 a Callableto be 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)方法......但如果你不需要,你不必。我更喜欢这个,因为它允许你有一个使用你的日志框架等的实现。

于 2014-12-19T05:49:40.320 回答
0

Callable 和Runnable彼此相似,都可以用于实现线程。在实现Runnable的情况下,您必须实现run()方法,但在 callable 的情况下,您必须实现call()方法,两种方法的工作方式相似,但可调用的call()方法具有更大的灵活性。它们之间存在一些差异。

Runnablecallable之间的区别如下 -

1) runnable的run()方法返回void,这意味着如果您希望线程返回可以进一步使用的东西,那么您别无选择 Runnable run()方法。有一个解决方案'Callable',如果你想以对象的形式返回任何东西,那么你应该使用 Callable 而不是 Runnable。可调用接口具有返回 Object 的方法 'call()'

方法签名 - Runnable->

public void run(){}

可调用->

public Object call(){}

2) 在Runnable run()方法的情况下,如果出现任何已检查的异常,则必须使用 try catch 块进行处理,但在Callable call()方法的情况下,您可以抛出已检查的异常,如下所示

 public Object call() throws Exception {}

3) Runnable来自传统的java 1.0版本,但callable来自带有Executer框架的Java 1.5版本。

如果您熟悉Executers ,那么您应该使用 Callable 而不是 Runnable

希望你能理解。

于 2018-10-23T08:23:13.610 回答