我对服务器进行了大量操作,我们称之为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
我怎样才能做到这一点?
答案 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()
,只有一个线程会获得它自己的数据。