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

时间:2016-04-12 13:38:07

标签: java multithreading synchronization locking

我对服务器进行了大量操作,我们称之为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

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:5)

我的相当不优雅的想法是在第一个电话进入时存储Future,并将同一个未来返回到第一个电话仍在等待时收到的其他电话。然后,当第一个呼叫完成时,丢弃此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;
  }
}

答案 1 :(得分:1)

一个不涉及任何额外线程的简单解决方案是使用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() {
    // ...
}

答案 2 :(得分:0)

您正在描述BlockingQueue

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

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