如何使用Spring-Boot清除@Async任务的所有已完成的Future结果?

时间:2018-08-19 17:58:12

标签: java spring multithreading spring-boot asynchronous

由于我在多线程领域经验不足,因此我很难理解@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,下面将简要介绍上面的迭代:

  1. 使用endless Iterator不断迭代futures列表(0、1、2 .. 8、9、10、0、1、2 ...)。
  2. 如果完成Future<Entry<Integer, String>>
    • 使用Map::put(替换条目)更新地图
    • Future<Entry<Integer, String>>移除List
  3. 如果列表futures为空,请停止无休止的迭代。

这个解决方案出奇地(我的第一个多线程实验)有效。

此解决方案线程安全且正确吗?使用ConcurrentHashMap是否足够?我不知道如何测试,除非将操作打印到控制台或日志中。如果在进行map方法调用时通过另一个@Async调用来更新update,将会使该方法synchronized足够吗?

1 个答案:

答案 0 :(得分:1)

对于我来说,方法看起来不错。如果由于使用update而在ConcurrentHashMap方法运行期间更新了映射,则什么也不会发生。如果要防止同时运行update,则可以使方法synchronized或使用一些锁定。您可以查看CompletableFutureallOf,它将为您管理期货,并在所有期货完成后发出新的期货。