Java中的并发和阻塞队列
我有一个典型的问题,线程将事件推送到第二个线程的传入队列。只是这一次,我对表演很感兴趣。我想要实现的是:Java中的并发和阻塞队列,java,queue,blocking,concurrency,Java,Queue,Blocking,Concurrency,我有一个典型的问题,线程将事件推送到第二个线程的传入队列。只是这一次,我对表演很感兴趣。我想要实现的是: 我想要并发访问队列,生产者推送,接收者弹出 当队列为空时,我希望消费者阻塞队列,等待生产者 我的第一个想法是使用LinkedBlockingQueue,但我很快意识到它不是并发的,性能受到了影响。另一方面,我现在使用的是ConcurrentLinkedQueue,但我仍在为每次发布支付wait()/notify()的费用。由于使用者在发现空队列时不会阻塞,因此我必须对锁进行同步和wait
- 我想要并发访问队列,生产者推送,接收者弹出
- 当队列为空时,我希望消费者阻塞队列,等待生产者
LinkedBlockingQueue
,但我很快意识到它不是并发的,性能受到了影响。另一方面,我现在使用的是ConcurrentLinkedQueue
,但我仍在为每次发布支付wait()
/notify()
的费用。由于使用者在发现空队列时不会阻塞,因此我必须对锁进行同步和wait()
。另一方面,制作人必须在每次发布时获得锁和notify()
。总的结果是,我正在支付
synchronized(lock){lock.notify()}
在每个出版物中,即使不需要
我想这里需要的是一个既阻塞又并发的队列。我设想一个push()
操作与ConcurrentLinkedQueue
中的操作一样工作,当push元素位于列表中的第一个时,向对象发送额外的notify()
。这样的检查,我认为已经存在于<代码> CONTRONCE LIKEDQueID中,因为推送需要连接下一个元素。因此,这将比每次在外部锁上同步快得多
这样的东西是否可行/合理 这是一个例子
我建议退房
就像@Rorick在他的评论中提到的那样,我相信所有这些实现都是并发的。我认为您对
LinkedBlockingQueue
的关注可能不合适。我认为您可以坚持使用java.util.concurrent.LinkedBlockingQueue
,而不必考虑您的疑虑。它是并行的。不过,我不知道它的性能。也许,BlockingQueue
的其他实现更适合您。它们不太多,所以进行性能测试和测量。我建议您查看newSingleThreadExecutor。它将处理为您排序的任务,如果您向执行者提交,您也将能够获得您正在寻找的阻塞行为。每当需要将数据从一个线程传递到另一个线程时,我都会使用ArrayBlockingQueue。使用put和take方法(如果已满/为空,则会阻止) 您可以从jsr166尝试LinkedTransferQueue:
它满足了您的需求,并减少了报价/投票操作的开销。
正如我从代码中看到的,当队列不是空的时,它使用原子操作来轮询元素。当队列为空时,它会旋转一段时间,如果不成功,则停止线程。
我认为这对你的情况有帮助。与这个答案相似,但有点不同。。我最终使用了一个执行器服务
。您可以使用Executors.newSingleThreadExecutor()
实例化一个。我需要一个并发队列来读取/写入缓冲区图像到文件,以及读取和写入的原子性。我只需要一个线程,因为文件IO比源文件net IO快几个数量级。此外,我更关心的是操作的原子性和正确性,而不是性能,但是这种方法也可以通过池中的多个线程来实现,以加快速度
要获取图像(请尝试捕获最终忽略):
Future-futureImage=executorService.submit(new Callable()){
@凌驾
公共BuffereImage调用()引发异常{
ImageInputStream is=新文件ImageInputStream(文件);
返回ImageIO.read(is);
}
})
image=futureImage.get();
要保存图像(请尝试捕获最终忽略):
Future futureWrite=executorService.submit(新的可调用(){
@凌驾
公共布尔调用(){
FileOutputStream os=新的FileOutputStream(文件);
返回ImageIO.write(image,getFileFormat(),os);
}
});
boolean wasWrite=futureWrite.get();
需要注意的是,您应该在finally块中刷新并关闭流。我不知道与其他解决方案相比它的性能如何,但它非常通用。为什么您认为java.util.concurrent.LinkedBlockingQueue不是并发的?从javadoc和源代码来看,我认为它是完全并发的。但我对性能一无所知。请参见,SynchronousQueue不是我想要的,因为它会在每次尝试发布时阻止我的制作人。SynchronousQueue看起来更像管道,而不是队列。看起来它不能包含待处理的任务,只能将单个任务从生产者“推送”到消费者。我之所以这样说,是因为我的吞吐量比ConcurrentLinkedQueue减少了大约8倍。我猜它只是为了提供线程安全性而在内部锁定整个东西。不过,您是对的,与ConcurrentLinkedQueue相比,它的性能可能更差。哪种类型的原因;-)无论您使用哪个队列,最终都会使用锁来支持等待新条目。(除非您忙着等待)锁实际上没有那么贵(锁大约0.5微秒),因此如果是性能问题,您的设计可能会有问题,例如创建更少的任务/找到向队列添加更少对象的方法/批处理您的工作。请注意,如果您想要更高的吞吐量,请在LinkedBColkingQueue上使用drainTo(),我们测量了一个应用程序的吞吐量增加了近500%,而不是从队列中去掉一个元素
Future<BufferedImage> futureImage = executorService.submit(new Callable<BufferedImage>() {
@Override
public BufferedImage call() throws Exception {
ImageInputStream is = new FileImageInputStream(file);
return ImageIO.read(is);
}
})
image = futureImage.get();
Future<Boolean> futureWrite = executorService.submit(new Callable<Boolean>() {
@Override
public Boolean call() {
FileOutputStream os = new FileOutputStream(file);
return ImageIO.write(image, getFileFormat(), os);
}
});
boolean wasWritten = futureWrite.get();