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;
}
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();
}
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<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 |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
11 回答
见解释here .
基本上,是的 . 请参阅this question的答案 . 和javadoc for Callable .
因为
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
)值 .A
Callable
需要实现call()
方法,而Runnable
需要实现run()
方法 .A
Callable
可以返回一个值,但Runnable
不能 .A
Callable
可以抛出已检查的异常,但Runnable
不能 .A
Callable
可以与ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
方法一起使用,但Runnable
不能 .我在另一个博客中发现了这个,可以解释一下这些differences:
虽然这两个接口都是由希望在不同的执行线程中执行的类实现的,但两个接口之间的差异很小:
Callable<V>
实例返回V
类型的结果,而Runnable
实例则不返回 .Callable<V>
实例可能会抛出已检查的异常,而Runnable
实例则不能Java的设计者觉得需要扩展
Runnable
接口的功能,但是他们不想影响Runnable
接口的使用,这可能就是为什么他们在Java 1.5中使用一个名为Callable
的独立接口的原因 . 改变已经存在的Runnable
.让我们看一下使用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方法中,就必须阻塞所有其他排队的项目执行 . 只有这样,该方法才会返回值 . 这是一种同步机制 .
Callable
接口声明了call()
方法,你需要提供泛型作为Object call()的类型应该返回 -另一方面,
Runnable
是声明run()
方法的接口,该方法在使用runnable创建一个Thread并在其上调用start()时调用 . 你也可以直接调用run()但是只执行run()方法是同一个线程 .总结一些值得注意的差异是
Runnable
对象不返回结果,而Callable
对象返回结果 .如果
Callable
对象可以抛出异常,则Runnable
对象不能抛出已检查的异常 .自Java 1.0以来一直存在
Runnable
接口,而Callable
仅在Java 1.5中引入 .几个相似之处包括
实现Runnable或Callable接口的类的实例可能由另一个线程执行 .
ExecutorService可以通过submit()方法执行Callable和Runnable接口的实例 .
两者都是功能接口,可以在Java8之后的Lambda表达式中使用 .
ExecutorService接口中的方法是
oracle文档中这些接口的用途:
Runnable接口应由其实例由
Thread
执行的任何类实现 . 该类必须定义一个名为run
的无参数的方法 .Callable:返回结果并可能抛出异常的任务 . 实现者定义一个没有名为call的参数的方法 .
Callable
接口类似于Runnable
,因为它们都是为其实例可能由另一个线程执行的类而设计的 . 但是,Runnable
不会返回结果,也不能抛出已检查的异常 .其他差异:
Runnable
来创建Thread . 但是你不能通过传递Callable
作为参数来创建新的线程 . 您只能将Callable传递给ExecutorService
实例 .Example:
Runnable
进行点火和忘记通话 . 使用Callable
验证结果 .与
Runnable
不同,Callable
可以传递给invokeAll方法 . 方法invokeAny
和invokeAll
执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部完成琐碎差异:要实施的方法名称=>
run()
用于Runnable
和call()
用于Callable
.正如在此处已经提到的那样,Callable是相对较新的接口,它是作为并发包的一部分引入的 . Callable和Runnable都可以与执行程序一起使用 . 类Thread(实现Runnable本身)仅支持Runnable .
您仍然可以将Runnable与执行程序一起使用 . Callable的优点是您可以将其发送给执行程序并立即返回将在执行完成时更新的Future结果 . 使用Runnable可以实现相同的功能,但在这种情况下,您必须自己管理结果 . 例如,您可以创建将保存所有结果的结果队列 . 其他线程可以在此队列上等待并处理到达的结果 .
Java的设计者觉得需要扩展
Runnable
接口的功能,但是他们不想影响Runnable
接口的使用,这可能就是为什么他们在Java 1.5中使用一个名为Callable
的独立接口的原因 . 更改已存在的Runnable
接口,该接口自Java 1.0以来一直是Java的一部分 . sourceDifference 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()方法放入任务队列 .
Callable和 Runnable 都彼此相似,可以用于实现线程 . 在实现 Runnable 的情况下,您必须实现 run() 方法但是在可调用的情况下您必须实现 call() 方法,这两种方法都以类似的方式工作但可调用 call() 方法具有更大的灵活性 . 它们之间存在一些差异 .
Runnable 和 callable 的区别如下 -
1) runnable 的 run() 方法返回 void ,表示如果你想让你的线程返回一些你可以进一步使用的东西,那么你有 no choice with Runnable run() 方法 . 有一个解决方案 'Callable' ,如果你想以 object 的形式返回任何东西,那么你 should use Callable instead of Runnable . 可调用接口有方法 'call()' which returns Object .
方法签名 - Runnable->
Callable->
2)如果是 Runnable run() 方法,如果出现任何检查异常,那么你必须 need to handled with try catch block ,但是如果是 Callable call() 方法你 can throw checked exception 如下
3) Runnable 来自遗留 java 1.0 版本,但 callable 来自带有 Executer 框架的 Java 1.5 版本 .
如果你熟悉 Executers 那么你应该 use Callable instead of Runnable .
希望你能理解 .