我知道Callable允许返回值或检查异常,而Runnable则不允许。这个问题不是关于两个接口之间的区别,而是关于以下代码中值的顺序返回。
请查看以下代码段。
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> futureList = new ArrayList<Future<String>>();
for (int i=0;i<10;i++) {
Runner runner = new Runner(i);
Future<String> future = executorService.submit(runner);
futureList.add(future);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
}
此代码的Runner类如下所示。
public class Runner implements Callable<String> {
private int id;
public Runner(Integer id) {
this.id = id;
}
@Override
public String call() throws Exception {
Random randomWait = new Random();
Thread.sleep(randomWait.nextInt(5)*1000);
Random random = new Random();
int randomInt = random.nextInt(100);
return id + " - " + randomInt;
}
}
上述代码总是提供顺序响应,尽管执行它们的线程可能会睡不同的秒数。
Returned value is : 0 - 19
Returned value is : 1 - 88
Returned value is : 2 - 99
........
Returned value is : 9 - 42
但是通过比较,以下代码段提供了更有意义的响应,因为线程会睡眠不同的时间段。
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<10;i++) {
Runner runner = new Runner(i);
executorService.submit(runner);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
关于细分的跑步者类别如下。 公共类Runner实现了Runnable {
private int id;
public Runner(Integer id) {
this.id = id;
}
@Override
public void run() {
Random randomWait = new Random();
try {
Thread.sleep(randomWait.nextInt(5)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Runner : " + id + " Finished.");
}
}
正如预期的那样,该线程的响应是非连续的。
Runner : 5 Finished.
Runner : 9 Finished.
Runner : 1 Finished.
Runner : 3 Finished.
........
所以我的问题是为什么带有期货和可调用响应的第一个代码段始终是顺序的?在我看来,主线程等待直到执行所有线程的结束并提供顺序输出。但是在javadoc中没有提到它。如果响应类似于第二个,我可以理解它。
答案 0 :(得分:3)
首先,您明确创建具有有序ID的期货列表,然后按顺序迭代它:
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
除顺序ID外没有其他可能的结果。每次拨打integerFuture.get()
时,只要将来需要提供结果,呼叫就会阻止。
在第二个示例中,您从 Callable
中输出到控制台,因此您将按完成顺序输出。
答案 1 :(得分:1)
所以我的问题是为什么带有期货和可调用响应的第一个代码段始终是顺序的?
因为您按照提交顺序明确询问 Futures
的结果:
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
此处,Future.get()
将阻止,直到通话完成 - 并且您的列表是通过提交callables构建的; futureList.get(0)
始终是与提交的第一个可调用者相关的未来,无论它是否是完成的第一个。