可调用是否优于Runnable?

时间:2013-05-26 07:40:46

标签: java concurrency

我已经理解了Java中RunnableCallable接口之间的区别。从Java 1.5到Runnable接口已添加了其他功能,并且为了保持向后兼容性而被称为Callable

我现在的问题是我们有Callable界面,我们是否总是使用它?不使用Callable和使用Runnable的用例有哪些?

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

5 个答案:

答案 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.scheduleAtFixedRatescheduleWithFixedDelay仅接受Runnable

答案 3 :(得分:6)

我更喜欢Callable,但在极少数情况下,您可能需要CallableRunnable,您可以通过添加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

希望您能理解