Java 中的并发队列和阻塞队列

2022-09-01 14:35:09

我有一个经典的问题,一个线程将事件推送到第二个线程的传入队列。只是这一次,我对性能非常感兴趣。我想实现的是:

  • 我想要并发访问队列,生产者推送,接收器弹出。
  • 当队列为空时,我希望使用者阻塞到队列,等待生产者。

我的第一个想法是使用 ,但我很快意识到它不是并发的,性能受到影响。另一方面,我现在使用,但我仍在支付每个出版物的费用。由于使用者在找到空队列时不会阻塞,因此我必须同步并锁定。另一方面,制片人必须抓住每一份出版物的锁。总体结果是,我支付了每一份出版物的费用,即使不需要。LinkedBlockingQueueConcurrentLinkedQueuewait()notify()wait()notify()sycnhronized (lock) {lock.notify()}

我想这里需要的是一个既阻塞又并发的队列。我想象一个操作,当推送的元素是列表中的第一个元素时,对对象有一个额外的操作。我认为这样的检查已经存在于 中,因为推送需要与下一个元素连接。因此,这比每次在外部锁定上进行同步要快得多。push()ConcurrentLinkedQueuenotify()ConcurrentLinkedQueue

这样的东西可用/合理吗?


答案 1

我认为你可以坚持下去,不管你的怀疑。它是并发的。不过,我对它的性能一无所知。可能,其他 实现将更适合您。它们并不多,因此请进行性能测试和测量。java.util.concurrent.LinkedBlockingQueueBlockingQueue


答案 2

与此答案类似,https://stackoverflow.com/a/1212515/1102730 但略有不同。我最终使用了.您可以使用 实例化一个。我需要一个并发队列来读取/写入 BufferedImages 到文件,以及读取和写入的原子性。我只需要一个线程,因为文件IO比源,网络IO快几个数量级。此外,我更关心操作的原子性和正确性而不是性能,但这种方法也可以在池中的多个线程中完成,以加快速度。ExecutorServiceExecutors.newSingleThreadExecutor()

要获取图像(尝试捕获-最终省略)::

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

请务必注意,您应该在最终块中刷新并关闭流。我不知道与其他解决方案相比,它的性能如何,但它非常通用。


推荐