Java BlockingQueue中工作项的并发顺序处理
我有一个系统的一部分,它在工作线程中处理输入项的Java BlockingQueue中工作项的并发顺序处理,java,performance,concurrency,queue,Java,Performance,Concurrency,Queue,我有一个系统的一部分,它在工作线程中处理输入项的BlockingQueue,并将结果放入输出项的BlockingQueue,其中相关代码(简化)如下所示: while(running()){ InputObject a=inputQueue.take();//从输入阻塞队列获取 OutputObject b=doProcessing(a);//处理该项 outputQueue.put(b);//放置在输出阻塞队列上 } doProcessing是该代码中的主要性能瓶颈,但队列项目的处理可以并行
BlockingQueue
,并将结果放入输出项的BlockingQueue
,其中相关代码(简化)如下所示:
while(running()){
InputObject a=inputQueue.take();//从输入阻塞队列获取
OutputObject b=doProcessing(a);//处理该项
outputQueue.put(b);//放置在输出阻塞队列上
}
doProcessing
是该代码中的主要性能瓶颈,但队列项目的处理可以并行化,因为处理步骤彼此独立
因此,我想改进这一点,以便项目可以由多个线程并发处理,但必须满足以下约束条件,即此不能更改输出的顺序(例如,我不能简单地让10个线程运行上述循环,因为这可能会导致根据处理时间对输出进行不同的排序)
在纯惯用Java中实现这一点的最佳方法是什么?创建X事件循环线程,其中X是可以并行处理的步骤数量 它们将被并行处理,但一个接一个的处理除外,即不在同一项目上。一个步骤将在一个项目上进行,而上一个步骤将在上一个项目上进行,以此类推 为了进一步优化它,您可以使用提供的并发队列,这些队列针对单生产者单消费者场景进行了优化(JDK的
BlockingQueue
实现支持多生产者多消费者)
来自
列表的并行流
保留顺序:
List<T> input = ...
List<T> output = input.parallelStream()
.filter(this::running)
.map(this::doProcessing)
.collect(Collectors.toList());
或者,您可以在它们全部处理完毕后订购(如果可以相互比较):
实现比较的一种简单方法是为输入队列中的每个元素分配一个渐进ID。谢谢您的回答-我知道这是如何工作的,但这似乎不允许并行执行单个处理步骤,而是将处理步骤分为不同的阶段(这是一个有趣的想法,但不是我想要的)。如果第二个任务在第一个任务之前完成,那么执行第二个任务的线程是否应该阻塞?或者执行第二个任务的线程是否应该继续执行另一个任务,并让执行第一个任务的线程处理第一个任务和第二个任务的结果排队?请注意,在这两种方法中,我都让线程执行
doProcess
负责将OutputObject
排队。最好没有工作线程阻塞(我假设是某种线程池,因此我们希望线程完成doProcessing
工作后立即返回池)。假设没有更多的输入等待处理,驱动队列的主线程阻塞也没关系。我提出了这样的想法:。这就是您要寻找的吗?注意,我没有严格测试代码,但它似乎可以工作。我也不确定是否有更高级别的构造可以简单地实现在我创建的Task
类中(例如,我尝试使用CompletableFuture
,但失败)。基本上,我所做的是创建一个任务的伪链接列表,根据需要完成后续任务。
// Thread 2
while (running()) {
InputObject a = queue1.take();
OutputObject b = doProcessingStep2(a);
queue2.put(b);
}
// Thread 3
while (running()) {
InputObject a = queue2.take();
OutputObject b = doProcessingStep3(a);
outputQueue.put(b);
}
List<T> input = ...
List<T> output = input.parallelStream()
.filter(this::running)
.map(this::doProcessing)
.collect(Collectors.toList());
outputQueue = new PriorityBlockingQueue<>();
outputQueue.drainTo(outputList);
outputList.sort(null);