Java"分层队列"实现快速生产者,减缓消费者

joe*_*joe 5 java queue concurrency multithreading threadpool

我有一个生产者 - 消费者场景,生产者生产的速度比消费者消费的快得多.通常,解决方案是使生产者阻止,因为生产者/消费者场景的运行速度与最慢的组件一样快.限制或阻止生产者并不是一个好的解决方案,因为我们的应用程序为消费者提供了足够的时间来赶上.

这是一个图表,描绘了我们的应用程序中的完整"阶段"与更常见的场景:

      Our Application                 Common Scenario
 2N +--------+--------+
    |PPPPPPPP|oooooooo|                                         P = Producer
    |PPPPPPPP|oooooooo|                                         C = Consumer
  N +--------+--------+      N +--------+--------+--------+     o = Other Work
    |CPCPCPCP|CCCCCCCC|        |CPCPCPCP|CPCPCPCP|oooooooo|     N = number of tasks
    |CPCPCPCP|CCCCCCCC|        |CPCPCPCP|CPCPCPCP|oooooooo|
    -------------------        ----------------------------
    0       T/2       T        0       T/2       T      3T/2
Run Code Online (Sandbox Code Playgroud)

我们的想法是通过不抑制生产者来最大化吞吐量.

我们的任务运行的数据很容易被序列化,因此我计划实现一个文件系统解决方案,以便溢出所有无法立即满足的任务.

我正在使用具有最大容量的Java ThreadPoolExecutor,BlockingQueue以确保我们不会耗尽内存.问题是在实施这样的"分层"的队列,在那里是可以在内存中排队的任务是如此立即执行,否则数据被排队在磁盘上.

我想出了两个可能的解决方案:

  1. 实现一个BlockingQueue从无到有,使用LinkedBlockingQueueArrayBlockingQueue实施作为参考.这可能就像在标准库中复制实现并添加文件系统读/写一样简单.
  2. 继续使用标准的BlockingQueue实施,实现一个独立的FilesystemQueue存储我的数据,并使用一个或多个线程出列文件,创建RunnableS和使用他们排队ThreadPoolExecutor.

这些都是合理的,是否有更好的方法?

小智 2

一个选项是按照Dimitar Dimitrov的建议,使用内存标志来增加可用堆空间大小,例如 -Xmxjava -Xmx2048m

来自Oracle 文档:请注意,JVM 使用的内存不仅仅是堆。例如,Java 方法、线程堆栈和本机句柄是在与堆以及 JVM 内部数据结构分开的内存中分配的。

这也是java堆内存如何分类图表。

在此输入图像描述


第二个选项是使用实现所需功能的库。为此,您可以使用Ashes-queue

项目概述来看:这是一个简单的 FIFO 实现,具有持久的支持。也就是说,如果队列已满,溢出的消息将被持久化,当有可用槽时,它们将被放回到内存中。


第三个选项创建您自己的实现。就此而言,您可以预览此线程,它将指导您实现该目的。

您的建议包含在最后的第三个选项中。两者都有道理。从实现的角度来看,您应该选择第一个选项,因为它将保证更容易的实现和简洁的设计。