首页 文章

Java中Runnable和Callable接口之间的区别

提问于
浏览
418

在Java中设计并发线程时使用 RunnableCallable 接口有什么区别,为什么要选择其中一个呢?

11 回答

  • 237

    见解释here .

    Callable接口类似于Runnable,因为它们都是为其实例可能由另一个线程执行的类而设计的 . 但是,Runnable不会返回结果,也不会抛出已检查的异常 .

  • 71

    Runnable和Callable的应用程序有什么不同 . 仅与Callable中存在的return参数有区别吗?

    基本上,是的 . 请参阅this question的答案 . 和javadoc for Callable .

    如果Callable可以完成Runnable所做的一切,那么需要两者兼得?

    因为 Runnable 接口 cannot 做了 Callable 所做的一切!

    Runnable 自Java 1.0以来一直存在,但 Callable 仅在Java 1.5中引入...以处理 Runnable 不支持的用例 . 从理论上讲,Java团队可能已经改变了 Runnable.run() 方法的签名,但这会破坏与1.5之前的代码的二进制兼容性,在将旧的Java代码迁移到新的JVM时需要重新编码 . 这是一个很大的不 - 不 . Java努力向后兼容......而且这是商业计算的最大卖点 .

    而且,显然,有一些用例,其中任务不需要返回结果或抛出已检查的异常 . 对于这些用例,使用 Runnable 比使用 Callable<Void> 更简洁,并从 call() 方法返回虚拟( null )值 .

  • 26
    • A Callable 需要实现 call() 方法,而 Runnable 需要实现 run() 方法 .

    • A Callable 可以返回一个值,但 Runnable 不能 .

    • A Callable 可以抛出已检查的异常,但 Runnable 不能 .

    • A Callable 可以与 ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks) 方法一起使用,但 Runnable 不能 .

    public interface Runnable {
        void run();
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }
    
  • 390

    我在另一个博客中发现了这个,可以解释一下这些differences

    虽然这两个接口都是由希望在不同的执行线程中执行的类实现的,但两个接口之间的差异很小:

    • Callable<V> 实例返回 V 类型的结果,而 Runnable 实例则不返回 .

    • Callable<V> 实例可能会抛出已检查的异常,而 Runnable 实例则不能

    Java的设计者觉得需要扩展 Runnable 接口的功能,但是他们不想影响 Runnable 接口的使用,这可能就是为什么他们在Java 1.5中使用一个名为 Callable 的独立接口的原因 . 改变已经存在的 Runnable .

  • 5

    让我们看一下使用Runnable和Callable的位置 .

    Runnable和Callable都运行在与调用线程不同的线程上 . 但是Callable可以返回一个值,而Runnable则不能 . 那么这真的适用于哪里呢?

    Runnable :如果你有一个fire and forget任务,那么使用Runnable . 将代码放在Runnable中,当调用run()方法时,您可以执行任务 . 执行任务时调用线程实际上并不关心 .

    Callable :如果您尝试从任务中检索值,请使用Callable . 现在可以自行调用不会起作用 . 你将需要一个围绕Callable的Future,并在future.get()上获取你的值 . 这里调用线程将被阻塞,直到Future返回结果,而结果又等待Callable的call()方法执行 .

    因此,考虑一个目标类的接口,其中定义了Runnable和Callable包装方法 . 调用类会随机调用你的接口方法,不知道哪个是Runnable,哪个是Callable . Runnable方法将异步执行,直到调用Callable方法 . 这里调用类的线程将阻塞,因为您正在从目标类中检索值 .

    注意:在目标类中,您可以在单个线程执行程序上调用Callable和Runnable,使此机制类似于串行调度队列 . 因此,只要调用者调用Runnable包装的方法,调用线程就会非常快速地执行而不会阻塞 . 只要它调用一个Callable包裹在Future方法中,就必须阻塞所有其他排队的项目执行 . 只有这样,该方法才会返回值 . 这是一种同步机制 .

  • 14

    Callable 接口声明了 call() 方法,你需要提供泛型作为Object call()的类型应该返回 -

    public interface Callable<V> {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }
    

    另一方面, Runnable 是声明 run() 方法的接口,该方法在使用runnable创建一个Thread并在其上调用start()时调用 . 你也可以直接调用run()但是只执行run()方法是同一个线程 .

    public interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used 
         * to create a thread, starting the thread causes the object's 
         * <code>run</code> method to be called in that separately executing 
         * thread. 
         * <p>
         * The general contract of the method <code>run</code> is that it may 
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    

    总结一些值得注意的差异是

    • Runnable 对象不返回结果,而 Callable 对象返回结果 .

    • 如果 Callable 对象可以抛出异常,则 Runnable 对象不能抛出已检查的异常 .

    • 自Java 1.0以来一直存在 Runnable 接口,而 Callable 仅在Java 1.5中引入 .

    几个相似之处包括

    • 实现Runnable或Callable接口的类的实例可能由另一个线程执行 .

    • ExecutorService可以通过submit()方法执行Callable和Runnable接口的实例 .

    • 两者都是功能接口,可以在Java8之后的Lambda表达式中使用 .

    ExecutorService接口中的方法是

    <T> Future<T> submit(Callable<T> task);
    Future<?> submit(Runnable task);
    <T> Future<T> submit(Runnable task, T result);
    
  • 9

    oracle文档中这些接口的用途:

    Runnable接口应由其实例由 Thread 执行的任何类实现 . 该类必须定义一个名为 run 的无参数的方法 .

    Callable:返回结果并可能抛出异常的任务 . 实现者定义一个没有名为call的参数的方法 . Callable 接口类似于 Runnable ,因为它们都是为其实例可能由另一个线程执行的类而设计的 . 但是, Runnable 不会返回结果,也不能抛出已检查的异常 .

    其他差异:

    • 您可以传递 Runnable 来创建Thread . 但是你不能通过传递 Callable 作为参数来创建新的线程 . 您只能将Callable传递给 ExecutorService 实例 .

    Example:

    public class HelloRunnable implements Runnable {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }   
    
        public static void main(String args[]) {
            (new Thread(new HelloRunnable())).start();
        }
    
    }
    
    • 使用 Runnable 进行点火和忘记通话 . 使用 Callable 验证结果 .

    Runnable 不同,

    • Callable 可以传递给invokeAll方法 . 方法 invokeAnyinvokeAll 执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部完成

    • 琐碎差异:要实施的方法名称=> run() 用于 Runnablecall() 用于 Callable .

  • 35

    正如在此处已经提到的那样,Callable是相对较新的接口,它是作为并发包的一部分引入的 . Callable和Runnable都可以与执行程序一起使用 . 类Thread(实现Runnable本身)仅支持Runnable .

    您仍然可以将Runnable与执行程序一起使用 . Callable的优点是您可以将其发送给执行程序并立即返回将在执行完成时更新的Future结果 . 使用Runnable可以实现相同的功能,但在这种情况下,您必须自己管理结果 . 例如,您可以创建将保存所有结果的结果队列 . 其他线程可以在此队列上等待并处理到达的结果 .

  • 13
    +-------------------------------------+--------------------------------------------------------------------------------------------------+
    |              Runnable               |                                           Callable<T>                                            |
    +-------------------------------------+--------------------------------------------------------------------------------------------------+
    | Introduced in Java 1.0 of java.lang | Introduced in Java 1.5 of java.util.concurrent library                                           |
    | Runnable cannot be parametrized     | Callable is a parametrized type whose type parameter indicates the return type of its run method |
    | Runnable has run() method           | Callable has call() method                                                                       |
    | Runnable.run() returns void         | Callable.call() returns a value of Type T                                                        |
    | Can not throw Checked Exceptions    | Can throw Checked Exceptions                                                                     |
    +-------------------------------------+--------------------------------------------------------------------------------------------------+
    

    Java的设计者觉得需要扩展 Runnable 接口的功能,但是他们不想影响 Runnable 接口的使用,这可能就是为什么他们在Java 1.5中使用一个名为 Callable 的独立接口的原因 . 更改已存在的 Runnable 接口,该接口自Java 1.0以来一直是Java的一部分 . source

  • 0

    Difference between Callable and Runnable are following:

    • 在JDK 5.0中引入了Callable,但在JDK 1.0中引入了Runnable

    • Callable有call()方法,但Runnable有run()方法 .

    • Callable有call方法,它返回值但Runnable有run方法,它不返回任何值 .

    • 调用方法可以抛出已检查的异常但是run方法不能抛出已检查的异常 .

    • Callable使用submit()方法放入任务队列但Runnable使用execute()方法放入任务队列 .

  • 3

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

    Runnablecallable 的区别如下 -

    1) runnablerun() 方法返回 void ,表示如果你想让你的线程返回一些你可以进一步使用的东西,那么你有 no choice with Runnable run() 方法 . 有一个解决方案 'Callable' ,如果你想以 object 的形式返回任何东西,那么你 should use Callable instead of Runnable . 可调用接口有方法 'call()' which returns Object .

    方法签名 - Runnable->

    public void run(){}
    

    Callable->

    public Object call(){}
    

    2)如果是 Runnable run() 方法,如果出现任何检查异常,那么你必须 need to handled with try catch block ,但是如果是 Callable call() 方法你 can throw checked exception 如下

    public Object call() throws Exception {}
    

    3) Runnable 来自遗留 java 1.0 版本,但 callable 来自带有 Executer 框架的 Java 1.5 版本 .

    如果你熟悉 Executers 那么你应该 use Callable instead of Runnable .

    希望你能理解 .

相关问题