我有一个线程将事件推送到第二个线程的传入队列的经典问题。只有这一次,我对表现很感兴趣。我想要实现的是:
我的第一个想法是使用LinkedBlockingQueue
,但我很快意识到它不是并发的,而且性能受到了影响。另一方面,我现在使用ConcurrentLinkedQueue
,但我仍然在每个出版物上支付wait()
/ notify()
的费用。由于消费者在找到空队列时没有阻止,我必须同步并wait()
锁定。另一方面,生产者必须在每个出版物上获得锁定和notify()
。总体结果是我付出了代价
每个出版物中sycnhronized (lock) {lock.notify()}
,即使不需要也是如此。
我想这里需要的是一个阻塞和并发的队列。我想象一个push()
操作在ConcurrentLinkedQueue
中工作,当推送元素是列表中的第一个时,对象的额外notify()
。我认为这样的检查已经存在于ConcurrentLinkedQueue
中,因为推送需要连接下一个元素。因此,这比每次在外部锁上同步要快得多。
这样的事情/合理吗?
答案 0 :(得分:12)
我认为无论你有什么疑问,你都可以坚持java.util.concurrent.LinkedBlockingQueue
。它是并发的。虽然,我不知道它的表现。可能BlockingQueue
的其他实现更适合您。其中没有太多,所以进行性能测试和测量。
答案 1 :(得分:6)
与此答案类似https://stackoverflow.com/a/1212515/1102730但有点不同......我最终使用了ExecutorService
。您可以使用Executors.newSingleThreadExecutor()
实例化一个。我需要一个并发队列来读取/写入BufferedImages文件,以及读取和写入的原子性。我只需要一个线程,因为文件IO比源,网络IO快几个数量级。此外,我更关注动作的原子性和正确性而不是性能,但是这种方法也可以通过池中的多个线程来完成,以加快速度。
获取图像(Try-Catch-Finally省略):
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();
保存图像(Try-Catch-Finally missing):
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();
重要的是要注意你应该在finally块中刷新和关闭你的流。与其他解决方案相比,我不知道它的表现如何,但它非常通用。
答案 2 :(得分:5)
我建议你看看ThreadPoolExecutor newSingleThreadExecutor。它将处理为您订购的任务,如果您向执行者提交Callables,您将能够获得您正在寻找的阻止行为。
答案 3 :(得分:4)
您可以尝试jsr166中的LinkedTransferQueue:http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166y/
它满足您的要求,并且提供/轮询操作的开销更少。 正如我从代码中看到的,当队列不为空时,它使用原子操作来轮询元素。当队列为空时,它会旋转一段时间并停止线程,如果不成功。 我认为这对你的情况有帮助。
答案 4 :(得分:3)
每当我需要将数据从一个线程传递到另一个线程时,我都会使用ArrayBlockingQueue。使用put和take方法(如果满/空将阻止)。
答案 5 :(得分:2)
这是list of classes implementing BlockingQueue
。
我建议您查看 SynchronousQueue
。
就像@Rorick在评论中提到的那样,我相信所有这些实现都是并发的。我认为您对LinkedBlockingQueue
的担忧可能不合适。