如何让其他线程等待给定的任务结果

How to make other threads wait for a given task result

我对服务器进行了繁重的操作,我们称之为 String getData(),我希望始终获得此数据的更新版本,因此我没有对调用应用缓存。

我现在的目标是避免同时有多个 getData 调用 运行。在第一次调用之后(但在第一次请求结束之前)完成所有调用以等待第一个结果。

示例:

Thread 1           Thread 2              Thread 3            
getData()
                   getData()[waiting]
                                         getData()[waiting]
result1 received   return result1        return result1
                   getData()
                   result2 received
                   return result2

我怎样才能做到这一点?

您描述的是 BlockingQueue 的功能。

BlockingQueue<Data> dataQueue = new ArrayBlockingQueue(1);

现在您需要做的就是dataQueue.take(),只有一个线程会获得它自己的数据。

我相当不雅的想法是在第一个电话打进来时存储一个 Future,并且 return 在第一个电话仍在挂起时收到的其他电话也有同样的未来。然后,当第一个调用完成时,丢弃这个 Future,并在下一个请求进来时创建一个新的:

class OneAtATime<T> {
  private final ExecutorService executor = Executors.newFixedThreadPool(1);

  private final Supplier<T> supplier;

  private Future<T> future;

  OneAtATime(Supplier<T> supplier) {
    this.supplier = supplier;
  }

  synchronized Future<T> submit() {
    if (future == null) {
      future = CompletableFuture.supplyAsync(supplier, executor);
      future.thenRunAsync(() -> {
        synchronized (JustOneExecutor.this) {
          future = null;
        }
      }, executor);
    }
    return future;
  }
}

一个不涉及任何额外线程的简单解决方案是使用 ConcurrentHashMap#computeIfAbsent:

private final ConcurrentHashMap<String, String> instance = 
    new ConcurrentHashMap<>(1);

private String getData() {
    final AtomicBoolean computed = new AtomicBoolean(false);
    String data = instance.computeIfAbsent("KEY", () -> { 
        String data = internalGetData(); 
        computed.set(true);
        return data;
    });
    if(computed.get()) {
       instance.clear();
    }
    return data;
}

private String internalGetData() {
    // ...
}