在Java中设计并发线程时,使用Runnable接口和Callable接口有什么区别,为什么你会选择其中一个而不是另一个?
当前回答
可调用接口声明call()方法,您需要提供泛型类型的对象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的线程并在其上调用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对象返回结果。 Runnable对象不能抛出检查异常,而Callable对象可以抛出检查异常 例外。 Runnable接口从Java 1.0开始就已经存在了,而Callable只是被引入的 在Java 1.5中。
相似之处包括
实现Runnable或Callable接口的类实例是潜在的 由另一个线程执行。 可调用接口和可运行接口的实例都可以由ExecutorService通过submit()方法执行。 两者都是功能接口,从Java8开始就可以在Lambda表达式中使用。
ExecutorService接口中的方法是
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
其他回答
请看这里的解释。
Callable接口类似于 可运行的,因为两者都是设计出来的 对于实例为的类 可能由另一个人执行 线程。然而,Runnable则不然 返回结果,且不能抛出 检查异常。
我在另一篇博客中发现了这一点,可以更好地解释这些差异:
虽然这两个接口都是由希望在不同的执行线程中执行的类实现的,但这两个接口之间有一些区别:
Callable<V>实例返回类型为V的结果,而Runnable实例则不会。 Callable<V>实例可能会抛出受控异常,而Runnable实例则不会
Java的设计者觉得有必要扩展Runnable接口的功能,但他们不想影响Runnable接口的使用,这可能就是为什么他们在Java 1.5中使用一个名为Callable的单独接口,而不是修改已经存在的Runnable的原因。
Runnable和Callable在应用程序中的区别是什么?是否只与返回参数在Callable中存在差异?
基本上,是的。请看这个问题的答案。Callable的javadoc。
如果Callable能做Runnable能做的所有事情,那么两者都需要什么呢?
因为Runnable接口不能做Callable所做的所有事情!
Runnable has been around since Java 1.0, but Callable was only introduced in Java 1.5 ... to handle use-cases that Runnable does not support. In theory, the Java team could have changed the signature of the Runnable.run() method, but this would have broken binary compatiblity with pre-1.5 code, requiring recoding when migrating old Java code to newer JVMs. That is a BIG NO-NO. Java strives to be backwards compatible ... and that's been one of Java's biggest selling points for business computing.
显然,在某些用例中,任务不需要返回结果或抛出检查过的异常。对于这些用例,使用Runnable比使用Callable<Void>和从call()方法返回一个虚拟(null)值更简洁。
+----------------------------------------+--------------------------------------------------------------------------------------------------+
| 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 generic value V |
| No way to propagate checked exceptions | Callable's call()“throws Exception” clause so we can easily propagate checked exceptions further | |
+----------------------------------------+--------------------------------------------------------------------------------------------------+
Java的设计者觉得有必要扩展Runnable接口的功能,但他们不想影响Runnable接口的使用,这可能就是为什么他们在Java 1.5中使用一个单独的名为Callable的接口,而不是改变已经存在的Runnable接口的原因,因为Runnable接口自Java 1.0以来一直是Java的一部分。源
正如这里已经提到的,Callable是一个相对较新的接口,它是作为并发包的一部分引入的。Callable和Runnable都可以与执行器一起使用。Thread类(实现Runnable本身)只支持Runnable。
您仍然可以将Runnable与执行程序一起使用。Callable的优点是,你可以将它发送给executor,并立即得到Future结果,当执行完成时,Future结果将被更新。Runnable也可以实现同样的功能,但在这种情况下,您必须自己管理结果。例如,您可以创建保存所有结果的结果队列。其他线程可以等待这个队列并处理到达的结果。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 自动化invokerrequired代码模式
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder