[英]Join multiple callback executions in a CompletableFuture
我有以下工作代碼:
DiscoveryCallback callback = new DiscoveryCallback();
Manager.discover(someparam, callback);
我想將此調用包裝到CompletableFuture中,以具有Rx-ish API與其他異步操作組合。
Manager.discover()是第三方庫的一種方法,實際上是本機函數的綁定,並且它在不同的線程中多次執行回調。
My DiscoveryCallback實現以下接口:
interface onFoundListerner {
onFound(List<Result> results)
onError(Throwable error)
}
我試圖將CompletableFuture<List<Result>>
的實例注入DiscoveryCallback,然后調用complete方法。 它對於一個回調執行工作正常,而其他回調則被忽略。
如何合並多個執行的結果並使包裝返回單個CompletableFuture?
異步隊列呢?
public class AsyncQueue<T> {
private final Object lock = new Object();
private final Queue<T> queue = new ArrayDeque<T>();
private CompletableFuture<Void> removeCf = new CompletableFuture<>();
public void add(T item) {
synchronized (lock) {
queue.add(item);
removeCf.complete(null);
}
}
public CompletableFuture<T> removeAsync() {
CompletableFuture<Void> currentCf = null;
synchronized (lock) {
T item = queue.poll();
if (item != null) {
return CompletableFuture.completedFuture(item);
}
else {
if (removeCf.isDone()) {
removeCf = new CompletableFuture<>();
}
currentCf = removeCf;
}
}
return currentCf
.thenCompose(v -> removeAsync());
}
}
在Java 9中,可以對removeAsync
返回的CompletableFuture
使用.completeOnTimeout(null, timeout, unit)
來具有超時機制。
在Java 9之前,您需要安排自己的超時時間。 這是帶有嵌入式超時調度程序的版本:
public class AsyncQueue<T> {
static final ScheduledExecutorService scheduledExecutorService;
static {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new ScheduledThreadFactory());
scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
scheduledExecutorService = Executors.unconfigurableScheduledExecutorService(scheduledThreadPoolExecutor);
}
static final class ScheduledThreadFactory implements ThreadFactory {
static AtomicInteger scheduledExecutorThreadId = new AtomicInteger(0);
static final synchronized int nextScheduledExecutorThreadId() {
return scheduledExecutorThreadId.incrementAndGet();
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable, "AsynchronousSemaphoreScheduler-" + nextScheduledExecutorThreadId());
thread.setDaemon(true);
return thread;
}
}
private final Object lock = new Object();
private final Queue<T> queue = new ArrayDeque<T>();
private CompletableFuture<Long> removeCf = new CompletableFuture<>();
public void add(T item) {
synchronized (lock) {
queue.add(item);
removeCf.complete(System.nanoTime());
}
}
public CompletableFuture<T> removeAsync(long timeout, TimeUnit unit) {
if (unit == null) throw new NullPointerException("unit");
CompletableFuture<Long> currentCf = null;
synchronized (lock) {
T item = queue.poll();
if (item != null) {
return CompletableFuture.completedFuture(item);
}
else if (timeout <= 0L) {
return CompletableFuture.completedFuture(null);
}
else {
if (removeCf.isDone()) {
removeCf = new CompletableFuture<>();
}
currentCf = removeCf;
}
}
long startTime = System.nanoTime();
long nanosTimeout = unit.toNanos(timeout);
CompletableFuture<T> itemCf = currentCf
.thenCompose(endTime -> {
long leftNanosTimeout = nanosTimeout - (endTime - startTime);
return removeAsync(leftNanosTimeout, TimeUnit.NANOSECONDS);
});
ScheduledFuture<?> scheduledFuture = scheduledExecutorService
.schedule(() -> itemCf.complete(null), timeout, unit);
itemCf
.thenRun(() -> scheduledFuture.cancel(true));
return itemCf;
}
public CompletableFuture<T> removeAsync() {
CompletableFuture<Long> currentCf = null;
synchronized (lock) {
T item = queue.poll();
if (item != null) {
return CompletableFuture.completedFuture(item);
}
else {
if (removeCf.isDone()) {
removeCf = new CompletableFuture<>();
}
currentCf = removeCf;
}
}
return currentCf
.thenCompose(endTime -> removeAsync());
}
}
您可以從此類中重構調度程序,以與其他類共享調度程序,也許將其分解為一個單例,該單例使用在.properties
文件中設置的工廠,並且如果未配置,則使用示例中的默認值。
您可以使用ReentrantLock
而不是synchronized
聲明,以獲得性能的那一點點。 它僅在激烈爭用下才有意義,但是AsyncQueue<T>
可以用於此類目的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.