等到阻止队列已满

时间:2014-08-07 21:03:47

标签: java multithreading synchronization blockingqueue

我正在寻找一种同步多个异步操作的方法。我想使用大小与我的操作相同的BlockingQueue,但是我可以等到队列满了?

我正在寻找类似反向阻挡队列的东西。

我需要收集每个线程的结果。 AsyncHandler是固定的,它已经是一个ThreadExecutor底层,我无法启动新的Threads。

//3 Times
makeAsync(new AsyncHandler() {
   onSuccess() {
     ..
     queue.put(result)
   }

   onFailure() {
     ..
   }
});

//Blocking till the Queue is full
List<Results> = queue.takeAll()

奖金问题:当我的一个请求失败时,我需要一种方法来结束等待

4 个答案:

答案 0 :(得分:1)

我从来没有必要做过这类事情,但是你可能会使用各种线程中的CountDownLatchCyclicBarrier来运气。

答案 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()方法来倒计时这个锁存器。主要方法就是等待它完成。

说了上面的话,你的程序结构闻起来不太好。