【问题标题】:How to clear out all the finished Future results of @Async tasks with Spring-Boot?如何使用 Spring-Boot 清除 @Async 任务的所有已完成的 Future 结果?
【发布时间】: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,上面的迭代简述如下:

  1. 使用endless Iterator 无休止地迭代futures 列表(0, 1, 2 .. 8, 9, 10, 0, 1, 2...)。
  2. 如果Future&lt;Entry&lt;Integer, String&gt;&gt; 完成:
    • 使用替换条目的Map::put 更新地图
    • List 中删除Future&lt;Entry&lt;Integer, String&gt;&gt;
  3. 如果列表futures 为空,则停止无限迭代。

这个解决方案令人惊讶(我的第一个多线程实验)有效。

此解决方案线程安全且方法正确吗? ConcurrentHashMap 的使用是否足够?除非将操作打印到控制台或日志,否则我不知道如何测试。如果mapupdate 方法调用的时刻被另一个@Async 调用更新,可能会发生什么情况——使synchronized 方法足够?

【问题讨论】:

    标签: java spring multithreading spring-boot asynchronous


    【解决方案1】:

    对我来说,方法看起来不错。如果在 update 方法运行期间更新地图,则不会发生任何事情,因为使用了 ConcurrentHashMap。如果您想防止同时运行update,您可以制作方法synchronized 或使用一些锁。您可以查看CompletableFutureallOf,它将为您管理期货并在所有期货完成后发出新的期货。

    【讨论】:

    • 感谢您的回答。您确定 ConcurrentHashMap 足以满足此用例吗?无论如何,请给我 +1,让我很荣幸能在 10k 人中让你感动 ;))
    • 请注意,我不想等待所有的期货,因为一个人可能会立即完成,而另一个人可能会在一分钟内完成。我想要持续更新。
    猜你喜欢
    • 2020-11-14
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 2018-11-10
    相关资源
    最近更新 更多