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以确保我们不会耗尽内存.问题是在实施这样的"分层"的队列,在那里是可以在内存中排队的任务是如此立即执行,否则数据被排队在磁盘上.
我想出了两个可能的解决方案:
BlockingQueue从无到有,使用LinkedBlockingQueue或ArrayBlockingQueue实施作为参考.这可能就像在标准库中复制实现并添加文件系统读/写一样简单.BlockingQueue实施,实现一个独立的FilesystemQueue存储我的数据,并使用一个或多个线程出列文件,创建RunnableS和使用他们排队ThreadPoolExecutor.这些都是合理的,是否有更好的方法?
小智 2
第一个选项是按照Dimitar Dimitrov的建议,使用内存标志来增加可用堆空间大小,例如 -Xmxjava -Xmx2048m
来自Oracle 文档:请注意,JVM 使用的内存不仅仅是堆。例如,Java 方法、线程堆栈和本机句柄是在与堆以及 JVM 内部数据结构分开的内存中分配的。
这也是java堆内存如何分类的图表。
第二个选项是使用实现所需功能的库。为此,您可以使用Ashes-queue
从项目概述来看:这是一个简单的 FIFO 实现,具有持久的支持。也就是说,如果队列已满,溢出的消息将被持久化,当有可用槽时,它们将被放回到内存中。
第三个选项是创建您自己的实现。就此而言,您可以预览此线程,它将指导您实现该目的。
您的建议包含在最后的第三个选项中。两者都有道理。从实现的角度来看,您应该选择第一个选项,因为它将保证更容易的实现和简洁的设计。