如何让其他线程等待给定的任务结果
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() {
// ...
}
我对服务器进行了繁重的操作,我们称之为 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() {
// ...
}