关于多线程:Java中可运行接口与可调用接口的区别

The difference between the Runnable and Callable interfaces in Java

在设计Java中的并发线程时,使用EDCOX1 0和EDCOX1 1接口的区别是什么?为什么要选择另一个?


请参阅此处的说明。

The Callable interface is similar to
Runnable, in that both are designed
for classes whose instances are
potentially executed by another
thread. A Runnable, however, does not
return a result and cannot throw a
checked exception.


What are the differences in the applications of Runnable and Callable. Is the difference only with the return parameter present in Callable?

基本上,是的。看看这个问题的答案。还有雅瓦多,以东王的子孙(7)。

What is the need of having both if Callable can do all that Runnable does?

因为Runnable接口不能做Callable所做的一切!

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

而且,很明显,在一些用例中,任务不需要返回结果或抛出检查过的异常。对于这些用例,使用Runnable比使用Callable和从call()方法返回虚拟值(null更简洁。


  • Callable需要实现call()方法,Runnable需要实现run()方法。
  • Callable可以返回值,但Runnable不能返回值。
  • Callable可以抛出已检查的异常,但Runnable不能。
  • Callable可用于ExecutorService#invokeXXX(Collection> tasks)方法,但Runnable不能。

    1
    2
    3
    4
    5
    6
    7
    public interface Runnable {
        void run();
    }

    public interface Callable<V> {
        V call() throws Exception;
    }


我在另一个博客中发现了这一点,它可以解释更多这些差异:

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

  • Callable实例返回V类型的结果,而Runnable实例不返回。
  • Callable实例可以抛出检查的异常,而Runnable实例不能

Java的设计者感觉需要扩展EDCOX1 2接口的能力,但是它们不想影响EDCOX1×2接口的使用,这可能是他们为什么要在Java 1.5中拥有一个单独的接口名为EDCOX1×7的接口,而不是改变已经存在的EDCOX1×2。


让我们看看在哪里可以使用runnable和callable。

可运行和可调用都在不同于调用线程的线程上运行。但是callable可以返回值,runnable不能。那么,这到底在哪里适用呢?

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

可调用:如果您试图从任务中检索值,请使用可调用。现在,可自行调用将无法完成该任务。您将需要一个围绕可调用对象的未来,并获得未来的价值观。获取()。在这里,调用线程将被阻塞,直到将来返回结果,而结果又等待Callable的call()方法执行。

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

注意:在目标类中,您可以在单个线程执行器上调用callable和runnable,使这个机制类似于串行调度队列。因此,只要调用方调用可运行的包装方法,调用线程就可以快速执行而不阻塞。一旦调用一个包装在未来方法中的可调用项,它就必须阻塞,直到执行所有其他排队项为止。只有这样,方法才会返回值。这是一种同步机制。


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

可运行接口应该由任何类实现,这些类的实例将由Thread执行。类必须定义一个不包含名为run的参数的方法。

可调用:返回结果并可能引发异常的任务。实现者定义了一个没有被调用的参数的方法。Callable接口类似于Runnable,因为这两个接口都是为可能由另一个线程执行实例的类设计的。但是,Runnable不返回结果,也不能抛出已检查的异常。

其他差异:

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

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部任务完成。

  • 细微差别:对于Runnable要实现的方法名=>run(),对于Callable要实现的方法名=>call()


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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()方法的接口,该方法在使用可运行线程创建线程并对其调用start()时调用。也可以直接调用run(),但只执行run()方法的线程是相同的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public interface Runnable {
        /**
         * When an object implementing interface <wyn>Runnable</wyn> is used
         * to create a thread, starting the thread causes the object's
         * <wyn>run</wyn> method to be called in that separately executing
         * thread.
         * <p>

         * The general contract of the method <wyn>run</wyn> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */

        public abstract void run();
    }

    总的来说,很少有显著的区别是

  • Runnable对象不返回结果,而Callable对象返回结果。
  • Callable对象可以抛出例外。
  • 自从Java 1以来,EDCOX1的2接口一直存在,而EDCOX1 0的引用仅被引入。在Java 1.5中。
  • 一些相似之处包括

  • 实现可运行或可调用接口的类的实例可能是由另一个线程执行。
  • ExecutorService可以通过submit()方法执行可调用和可运行接口的实例。
  • 这两个接口都是函数接口,可以在lambda表达式中使用,因为java8。
  • ExecutorService接口中的方法是

    1
    2
    3
    <T> Future<T> submit(Callable<T> task);
    Future<?> submit(Runnable task);
    <T> Future<T> submit(Runnable task, T result);

    正如前面提到的,Callable是一个相对较新的接口,它是作为并发包的一部分引入的。可调用和可运行都可以与执行器一起使用。类线程(实现可运行的本身)只支持可运行的。

    您仍然可以对执行器使用runnable。Callable的优点是,您可以将其发送给执行器,并立即返回在执行完成后将更新的未来结果。同样的方法也可以用runnable实现,但在这种情况下,您必须自己管理结果。例如,您可以创建保存所有结果的结果队列。其他线程可以在此队列上等待并处理到达的结果。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    +-------------------------------------+--------------------------------------------------------------------------------------------------+
    |              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的设计者感觉需要扩展EDCOX1 3接口的能力,但是它们不想影响EDCOX1 3接口的使用,这可能是他们为什么要在Java 1.5中拥有一个单独的接口名为EDCOX1×2的接口,而不是改变已经存在的EDCOX1和3的接口。自从Java 1以来,是Java的一部分。来源


    可调用和可运行的区别如下:

  • JDK 5.0中引入了可调用,JDK 1.0中引入了可运行
  • Callable有call()方法,但runnable有run()方法。
  • callable具有返回值的call方法,但runnable具有不返回任何值的run方法。
  • 调用方法可以引发选中的异常,但运行方法不能引发选中的异常。
  • 可调用使用submit()方法放入任务队列,但可运行使用execute()方法放入任务队列。

  • 可调用和可运行两者都很相似,可以用于实现线程。在实现runnable的情况下,必须实现run()方法,但在可调用的情况下,必须实现call()方法,这两种方法的工作方式相似,但call()方法有更大的灵活性,两者之间有一些区别。

    可运行和可调用的区别如下--

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

    方法签名-可运行的>

    1
    public void run(){}

    可调用的>

    1
    public Object call(){}

    2)对于runnable run()方法,如果出现任何选中的异常,则必须使用try catch块进行处理,但是对于callable call()方法,可以按如下方式引发选中的异常

    1
     public Object call() throws Exception {}

    3)RunnFabess来自遗留Java 1版本,但可调用的Java 1.5版本采用ExcUnter框架。

    如果您熟悉执行器,那么应该使用Callable而不是Runnable。

    希望你能理解。