我正在用Java做一些多线程工作,我对Future get
方法有疑问。
我有一个ExecutorSevice
提交了n个Callable。提交返回一个Future
,该call
被添加到列表中(稍后在某些代码中)。 Callable的someMethod
方法遍历一个列表,并为列表中的每个项目调用CompletableFuture<T>
并返回一个call
。然后,将“可完成的未来”添加到地图中。
在循环结束时,uglyList
返回包含一堆CompletableFuture的地图。
因此,初始列表(<String, CompletableFuture<String>>
)包含n个get
的映射。
我的问题是,当我在uglyList
的元素上调用CompletableFutures
时,执行被阻止,直到访问了整个列表(作为参数传递给Callable)并且所有get
都具有被插入地图,对吧?
由于我有一个疑问,本示例中的CompletableFutures
是否也可能等待地图中
public class A {
private class CallableC implements Callable<Map<String, CompletableFuture<String>>> {
private List<String> listString;
Map<String, CompletableFuture<String>> futureMap;
public CallableC(List<String> listString) throws Exception {
this.listString = listString;
this.futureMap = new HashMap<>();
}
@Override
public Map<String, CompletableFuture<String>> call() throws Exception {
for (int j = 0; j < listString.size(); ++j) {
CompletableFuture<String> future = someMethod();
futureMap.put(listString.get(i), future);
}
return futureMap;
}
}
public void multiThreadMethod(List<String> items) throws Exception {
List<Future<Map<String, CompletableFuture<String>>>> uglyList = new ArrayList<>();
int coresNumber = (Runtime.getRuntime().availableProcessors());
// This method split a List in n subList
List<List<String>> splittedList = split(items, coresNumber);
ExecutorService executor = Executors.newFixedThreadPool(coresNumber);
try {
for (int i = 0; i < coresNumber; ++i) {
threads.add(executor.submit(new CallableC(splittedList.get(i),)));
}
for (int i = 0; i < coresNumber; ++i) {
uglyList.get(i).get(); //here
}
} catch (Exception e) {
// YAY errors
}
finally {
executor.shutdown();
}
}
}
的完成?我不知道如何测试
if (Modernizr.video) {
// let's play some video!
} else {
// no native video support available :(
// maybe check for QuickTime or Flash instead
}
答案 0 :(得分:0)
当我调用uglyList的元素上的get时,执行被阻止,直到访问了整个列表(作为参数传递给Callable)并且所有CompletableFutures已插入到地图中,对吧?
是的,这是正确的。 get()
将等待Callable
的完成,在您的情况下,这意味着CallableC#call()
方法的结束,当{无论这些CompletableFutures
的状态/完成情况如何,所有{1}}均已创建并插入到futureMap
中。
此示例中的get是否有可能也等待地图中CompletableFutures的完成?
可以实现此目的,但必须要有附加代码。
在代码中执行此操作的最小方法是在任务内的CompletableFuture
上添加联接调用。
CompletableFuture
另一种方法是在最后等待(为简洁起见,我跳过异常处理):
@Override
public Map<String, CompletableFuture<String>> call() throws Exception {
for (int j = 0; j < listString.size(); ++j) {
CompletableFuture<String> future = someMethod();
futureMap.put(listString.get(j), future);
}
// This will wait for all the futures inside the map to terminate
try {
CompletableFuture.allOf(futureMap.values().toArray(new CompletableFuture[0])).join();
} catch (CompletionException e) {
// ignored - the status will be checked later on
}
return futureMap;
}
但是,如果可能的话,我将仅使用可完成的期货来简化整个代码,除非您有充分的理由以自己的方式来中断任务(使用列表,专用执行程序等)。 )。这可能看起来像这样(可能有一些错别字)
for (int i = 0; i < coresNumber; ++i) {
threads.add(executor.submit(new CallableC(splittedList.get(i),)));
}
// This will wait for all the futures to terminate (thanks to f.get())
// And then, all the completable futures will be added to an array of futures that will also be waited upon
CompletableFuture.allOf(
uglyList.stream().flatMap(f -> f.get().values().stream()).toArray(CompletableFuture[]::new)
).join();
这将替换问题中的整个代码。