我正在寻找一种同步多个异步操作的方法。我想使用大小与我的操作相同的BlockingQueue,但是我可以等到队列满了?
我正在寻找类似反向阻挡队列的东西。
我需要收集每个线程的结果。 AsyncHandler是固定的,它已经是一个ThreadExecutor底层,我无法启动新的Threads。
//3 Times
makeAsync(new AsyncHandler() {
onSuccess() {
..
queue.put(result)
}
onFailure() {
..
}
});
//Blocking till the Queue is full
List<Results> = queue.takeAll()
奖金问题:当我的一个请求失败时,我需要一种方法来结束等待
答案 0 :(得分:1)
我从来没有必要做过这类事情,但是你可能会使用各种线程中的CountDownLatch
或CyclicBarrier
来运气。
答案 1 :(得分:1)
如果您正在使用Java 8,请执行以下操作:
makeAsync
时,都会创建一个CompletableFuture<Result>
实例,并将其提供给AsyncHandler
,并让调用者也保留一个引用,比如列表。complete(result)
实例上调用CompletableFuture
。completeExceptionally(exception)
实例上调用CompletableFuture
。CompletableFuture.allOf(cfArray).join()
。不幸的是,这需要一个数组,而不是列表,所以你必须转换。如果任何一个任务因错误而完成,join()
调用将抛出异常。否则,您可以通过调用CompletableFuture
方法从各个get()
实例中收集结果。如果您没有Java 8,那么您将不得不推出自己的机制。将CountDownLatch
初始化为您即将启动的异步任务的数量。让每个异步任务将其结果(或异常或其他一些指示失败的方法)存储到线程安全的数据结构中,然后递减(&#39; countDown`)锁存器。让呼叫者等待锁存器达到零,然后收集结果和错误。这并不是非常困难,但您必须确定一种存储有效结果的方法,并记录是否发生错误,并且还要手动维护计数。
答案 2 :(得分:1)
您用
描述的内容//Blocking till the Queue is full
List<Results> results = queue.takeAll();
在语义上与“获取与队列容量一样多的项目”没有区别。如果您知道能力,您可以通过以下方式实现这一目标:
// preferably a constant which you also use to construct the bounded queue
int capacity;
...
List<Results> results = new ArrayList<>(capacity);
queue.drainTo(results, capacity);
while(result.size()<capacity)
queue.drainTo(results, capacity-result.size());
这将阻止它收到与capacity
一样多的项目,正如所说的那样,等待队列变满(大小等于其容量)并且取得所有项目。唯一的区别是队列变满的事件不能保证发生,例如,如果你打算对offer
项进行异步操作,直到队列满了,它就不会以这种方式工作。
如果你不知道容量,那你就不走运了。甚至没有保证任意BlockingQueue
是有界限的,阅读,它可能具有无限的容量。
另一方面,如果异步操作能够检测到它们何时完成,它们可以简单地在本地列表中收集项目,并将整个列表作为单个项目放入BlockingQueue<List<Results>>
完成。然后,等待它的代码只需要一个take
来获取整个列表。
答案 3 :(得分:0)
如果你可以修改methodAsync(),那么在每次将一些元素放入队列并让主线程等待这样的CountDownLatch之后,它就像使用CountDownLatch一样简单。
如果遗憾的是你无法修改methodAsync(),那么只需将队列包装并给它一个倒计时锁存器,然后覆盖add()方法来倒计时这个锁存器。主要方法就是等待它完成。
说了上面的话,你的程序结构闻起来不太好。