之间的差异可运行和可调用的接口在Java
-
02-07-2019 - |
题
之间的区别是什么使用 Runnable
和 Callable
接口的当设计并发线程,为什么你会选择一个比其他?
解决方案
请参阅此处的说明。
Callable接口类似于 Runnable,两者都是设计的 对于其实例为的类 可能由另一个人执行 线。 但是,Runnable没有 返回一个结果,不能扔一个 检查异常。
其他提示
中的返回参数
Runnable
和Callable
的应用程序有何不同。区别仅在于Runnable.run()
?
基本上,是的。请参阅此问题的答案。 javadoc for Callable<Void>
如果
null
能够完成call()
所做的一切,那么有什么需要?
因为<=>界面不能执行<=>所做的一切!
<=>自Java 1.0以来一直存在,但<=>仅在Java 1.5中引入...以处理<=>不支持的用例。从理论上讲,Java团队本可以更改<=>方法的签名,但这会破坏与1.5之前的代码的二进制兼容性,在将旧的Java代码迁移到新的JVM时需要重新编码。这是一个很大的不 - 不。 Java努力向后兼容......这也是Java商业计算的最大卖点之一。
显然,在某些情况下,任务不会需要来返回结果或抛出已检查的异常。对于这些用例,使用<=>比使用<=>更简洁,并从<=>方法返回虚拟(<=>)值。
- 一个
Callable
需要实现call()
方法的同时Runnable
需要实现run()
法。 - 一个
Callable
可以返回的价值,但一个Runnable
不能。 - 一个
Callable
可以扔的检查的例外,但一个Runnable
不能。 一个
Callable
可以使用ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
方法,但一个Runnable
不可能。public interface Runnable { void run(); } public interface Callable<V> { V call() throws Exception; }
我发现这个在另一个博客中这可以解释这一点这些 差异:
虽然这两个接口实现的类希望执行在不同的执行线,但几乎没有差异,两者之间的接口,这是:
- 一个
Callable<V>
实例返回的结果的类型V
, 而一个Runnable
实例没有。 - 一个
Callable<V>
实例可能会引发的检查的例外情况,而一个Runnable
实例不能
设计师们的Java感到需要扩大能力 Runnable
接口,但是他们不希望影响所使用的 Runnable
接口,可能这就是为什么他们就有一个单独的接口命名的 Callable
在Java1.5于改变已经存在的 Runnable
.
让我们看一下使用Runnable和Callable的位置。
Runnable和Callable都在与调用线程不同的线程上运行。但是Callable可以返回一个值,而Runnable则不能。那么这在哪里真的适用。
Runnable :如果您有一个fire and forget任务,那么请使用Runnable。将代码放在Runnable中,当调用run()方法时,您可以执行任务。执行任务时,调用线程实际上并不关心。
可调用:如果您尝试从任务中检索值,请使用Callable。现在可以自行调用不会起作用。你将需要一个围绕Callable的Future,并在future.get()上获取你的值。这里调用线程将被阻塞,直到Future返回结果,而结果又等待Callable的call()方法执行。
因此,请考虑一个目标类的接口,其中定义了Runnable和Callable包装方法。调用类会随机调用你的接口方法,不知道哪个是Runnable,哪个是Callable。 Runnable方法将异步执行,直到调用Callable方法。这里调用类的线程将阻塞,因为您正在从目标类中检索值。
注意:在目标类中,您可以在单个线程执行程序上调用Callable和Runnable,使此机制类似于串行调度队列。因此,只要调用者调用Runnable包装的方法,调用线程就会非常快速地执行而不会阻塞。一旦它调用了一个Callable裹在Future方法中,它就必须阻塞,直到所有其他排队的项都被执行。只有这样,该方法才会返回值。这是一种同步机制。
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();
}
总结一些值得注意的差异
- <=>对象不返回结果,而<=>对象返回结果。
- <=>对象不能抛出一个<=>对象可以抛出的已检查异常 异常。
- <=>接口自Java 1.0以来一直存在,而<=>仅被引入 在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);
来自oracle文档的这些接口的用途:
应实施 Runnable 界面由任何其实例打算由Thread
执行的类。该类必须定义一个没有参数的方法,名为run
。
Callable :A返回结果并可能抛出异常的任务。实现者定义一个没有名为call的参数的方法。
Callable
接口类似于Runnable
,因为它们都是为其实例可能由另一个线程执行的类而设计的。但是,ExecutorService
不返回结果,也不能抛出已检查的异常。
其他差异:
-
您可以传递
invokeAny
创建螺纹。但是你不能通过传递invokeAll
作为参数来创建新的线程。您只能将Callable传递给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(); } }
-
使用
call()
拨打电话和忘记电话。使用<=>验证结果。 -
<=>可以传递给不同的noreferrer“> invokeAll 方法。方法<=>和<=>执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部完成
-
微不足道的差异:要实施的方法名称= <!> gt; <=>用于<=>和<=>用于<=>。
醇>
正如之前已经提到的,Callable是一个相对较新的接口,它是作为并发包的一部分引入的。 Callable和Runnable都可以与执行程序一起使用。类Thread(实现Runnable本身)仅支持Runnable。
您仍然可以将Runnable与执行程序一起使用。 Callable的优点是您可以将其发送给执行程序并立即返回将在执行完成时更新的Future结果。使用Runnable可以实现相同的功能,但在这种情况下,您必须自己管理结果。例如,您可以创建将保存所有结果的结果队列。其他线程可以在此队列上等待并处理到达的结果。
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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
接口的功能,但是他们不想影响Callable
接口的使用,这可能就是他们为什么要单独使用的原因Java 1.5中名为<=>的接口,而不是更改现有的<=>接口,该接口自Java 1.0以来一直是Java的一部分。 来源
Callable和Runnable之间的区别如下:
- 在JDK 5.0中引入了Callable,但在JDK 1.0中引入了Runnable
- Callable有call()方法,但Runnable有run()方法。
- Callable具有call方法,该方法返回值但Runnable有run方法,该方法不返回任何值。
- call方法可以抛出已检查的异常,但run方法不能抛出已检查的异常。
- 可调用use()方法放入任务队列,但Runnable使用execute()方法放入任务队列。 醇>
Callable和 Runnable 两者相似,可用于实现线程。在实施 Runnable 的情况下,您必须实施 run()方法,但在可调用的情况下,您必须实现 call()方法,这两种方法都是如此以类似的方式工作但可调用的 call()方法具有更大的灵活性。它们之间存在一些差异。
可运行与可调用的区别如下 -
1) runnable 的 run()方法返回 void ,表示您希望线程返回可以进一步使用的内容然后你有没有选择使用Runnable run()方法。有一个解决方案'Callable',如果您想以对象的形式返回任何内容,那么应该使用Callable而不是Runnable 。可调用接口有方法'call()'返回Object 。
方法签名 - 可运行 - GT <!>;
public void run(){}
<!> - 可赎回GT;
public Object call(){}
2)如果是 Runnable run()方法,如果出现任何已检查的异常,那么您必须需要使用try catch block 进行处理,但是如果可调用的call()方法可以抛出已检查的异常,如下所示
public Object call() throws Exception {}
3) Runnable 来自旧的 java 1.0 版本,但可调用带有 Java 1.5 版本< strong> Executer 框架。
如果您熟悉执行者,那么您应该使用Callable而不是Runnable 。
希望你明白。
可运行(vs)可调用 进入点当我们使用的约执行部框架。
ExecutorService是subinterface的 Executor
, 接受这两个可运行和可调用的任务。
此前多线程可以实现使用的界面 Runnable
因为1.0, 但这里的问题是完成后,将螺纹的任务,我们是无法收取在线信息。为了收集的数据,我们可以使用的是静态的领域。
例如独立的线来收集每个学生的数据。
static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
Thread t1 = new Thread( new RunnableImpl(1), "T1" );
Thread t2 = new Thread( new RunnableImpl(2), "T2" );
Thread t3 = new Thread( new RunnableImpl(3), "T3" );
multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
multiTasksData.put("T2", new ArrayList() );
multiTasksData.put("T3", new ArrayList() );
}
要解决这个问题,他们已经引入了 Callable<V>
因为1.5 其返回的结果和可能会引发一个例外。
单抽象的方法 :这两个可调用和可运行的接口有一个抽象的方法,这意味着它们可用于lambda表达java8.
public interface Runnable { public void run(); } public interface Callable<Object> { public Object call() throws Exception; }
有几个不同的方式委派任务的执行来一个 ExecutorService.
execute(Runnable task):void
箱子新线,但不是块主线,或者叫线作为这种方法返回无效。submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
箱子新线和主块纹的时候你使用 未来。获得().
例的使用接口,以运行,可调用与执行框架。
class CallableTask implements Callable<Integer> {
private int num = 0;
public CallableTask(int num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
return num;
}
}
class RunnableTask implements Runnable {
private int num = 0;
public RunnableTask(int num) {
this.num = num;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
}
}
public class MainThread_Wait_TillWorkerThreadsComplete {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("Main Thread start...");
Instant start = java.time.Instant.now();
runnableThreads();
callableThreads();
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis());
System.out.println("Main Thread completed...");
}
public static void runnableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> f1 = executor.submit( new RunnableTask(5) );
Future<?> f2 = executor.submit( new RunnableTask(2) );
Future<?> f3 = executor.submit( new RunnableTask(1) );
// Waits until pool-thread complete, return null upon successful completion.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
public static void callableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<Integer> f1 = executor.submit( new CallableTask(5) );
Future<Integer> f2 = executor.submit( new CallableTask(2) );
Future<Integer> f3 = executor.submit( new CallableTask(1) );
// Waits until pool-thread complete, returns the result.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
}