Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的并发和阻塞队列_Java_Queue_Blocking_Concurrency - Fatal编程技术网

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();