【发布时间】:2019-01-25 23:20:53
【问题描述】:
由于我在多线程领域非常缺乏经验,所以我无法理解@Async 注释和方法的用法。
我有一些Map<Integer, String> map,我想使用异步方法调用更新这个map。此方法在带有int id 的页面上发出HTTP GET 请求,结果返回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,上面的迭代简述如下:
- 使用endless Iterator 无休止地迭代
futures列表(0, 1, 2 .. 8, 9, 10, 0, 1, 2...)。 - 如果
Future<Entry<Integer, String>>完成:- 使用替换条目的
Map::put更新地图 - 从
List中删除Future<Entry<Integer, String>>
- 使用替换条目的
- 如果列表
futures为空,则停止无限迭代。
这个解决方案令人惊讶(我的第一个多线程实验)有效。
此解决方案线程安全且方法正确吗? ConcurrentHashMap 的使用是否足够?除非将操作打印到控制台或日志,否则我不知道如何测试。如果map 在update 方法调用的时刻被另一个@Async 调用更新,可能会发生什么情况——使synchronized 方法足够?
【问题讨论】:
标签: java spring multithreading spring-boot asynchronous