由于我在多线程领域经验不足,因此我很难理解@Async
批注和方法的用法。
我有一些Map<Integer, String> map
,我想使用异步方法调用来更新此map
。此方法在具有HTTP GET
的页面上发出int id
请求,并返回String string
作为结果-它已更新为map
,我需要获取更新的结果值:>
@Async
public Future<Entry<Integer, String>> updateEntry(Integer key, String value) {
Entry<Integer, String> entry = // Method call updates String value (let's say HTTP GET request takes few seconds)
return new AsyncResult<Entry<Integer, String>>(entry);
}
由于使用this
调用此方法将不起作用,因此还有另一个类执行这些方法:
private final Map<Integer, String> map = new ConcurrentHashMap<>();
private void update() {
// KICK THE ASYNC METHODS UP
List<Future<Entry<Integer, String>>> futures = new ArrayList<>();
map.forEach((key, value) -> {
futures.add(asyncObject.updateEntry(value));
});
// FETCH THE RESULTS
Iterator<Future<Entry<Integer, String>>> iterator = futures.iterator();
while (iterator.hasNext()) {
Future<Entry<Integer, String>> future = iterator.next();
if (future.isDone()) {
try {
Entry<Integer, String> entry = future.get();
this.map.put(entry.getKey(), entry.getValue());
iterator.remove();
} catch (InterruptedException | ExecutionException e) {
// SH*T HAPPENS, LOG IT
}
}
if (!iterator.hasNext()) {
iterator = futures.iterator();
}
}
}
我将所有将来的结果存储在futures
中,该结果迟早会出现。我认为一种好方法是使用无尽的while-loop
来检查是否Future::isDone
,下面将简要介绍上面的迭代:
futures
列表(0、1、2 .. 8、9、10、0、1、2 ...)。Future<Entry<Integer, String>>
:
Map::put
(替换条目)更新地图Future<Entry<Integer, String>>
移除List
futures
为空,请停止无休止的迭代。这个解决方案出奇地(我的第一个多线程实验)有效。
此解决方案线程安全且正确吗?使用ConcurrentHashMap
是否足够?我不知道如何测试,除非将操作打印到控制台或日志中。如果在进行map
方法调用时通过另一个@Async
调用来更新update
,将会使该方法synchronized
足够吗?
答案 0 :(得分:1)
对于我来说,方法看起来不错。如果由于使用update
而在ConcurrentHashMap
方法运行期间更新了映射,则什么也不会发生。如果要防止同时运行update
,则可以使方法synchronized
或使用一些锁定。您可以查看CompletableFuture
和allOf
,它将为您管理期货,并在所有期货完成后发出新的期货。