在Java中设计并发线程时,使用Runnable接口和Callable接口有什么区别,为什么你会选择其中一个而不是另一个?
当前回答
+----------------------------------------+--------------------------------------------------------------------------------------------------+
| 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的一部分。源
其他回答
可调用接口声明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是一个相对较新的接口,它是作为并发包的一部分引入的。Callable和Runnable都可以与执行器一起使用。Thread类(实现Runnable本身)只支持Runnable。
您仍然可以将Runnable与执行程序一起使用。Callable的优点是,你可以将它发送给executor,并立即得到Future结果,当执行完成时,Future结果将被更新。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)值更简洁。
oracle文档中这些接口的用途:
可运行接口应该由任何类实现,其实例将由线程执行。该类必须定义一个名为run的无参数方法。
可调用:返回结果并可能抛出异常的任务。实现者定义一个不带参数的方法叫做call。 Callable接口与Runnable接口类似,因为两者都是为其实例可能由另一个线程执行的类设计的。然而,Runnable不返回结果,也不能抛出受控异常。
其他的差异:
You can pass Runnable to create a Thread. But you can't create new Thread by passing Callable as parameter. You can pass Callable only to ExecutorService instances. 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(); } } Use Runnable for fire and forget calls. Use Callable to verify the result. Callable can be passed to invokeAll method unlike Runnable. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete Trivial difference : method name to be implemented => run() for Runnable and call() for Callable.
推荐文章
- 如何在java中格式化持续时间?(如格式H:MM:SS)
- urlencoder .encode(字符串)已弃用,我应该使用什么代替?
- javax.transaction.Transactional vs . org.springframework.transaction.annotation.Transactional
- Java 8接口方法中不允许“同步”的原因是什么?
- 如何找到Java堆大小和内存使用(Linux)?
- 使用Enum实现单例(Java)
- RabbitMQ与通道和连接之间的关系
- 跨线程操作无效:控件“textBox1”从创建它的线程以外的线程访问
- buildSessionFactory()配置方法在Hibernate中已弃用?
- Spring MVC -如何获得所有的请求参数在一个地图在Spring控制器?
- 如何在Java中按两个字段排序?
- 文件之间的差异。路径中的分隔符和斜杠
- 在方法参数中使用NotNull注释
- Spring MVC中处理可选参数的@RequestParam
- Tomcat:如何查找正在运行的Tomcat版本?