这个问题与最新版本的 Java 有关。
30 个生产者线程将字符串推送到一个抽象队列。一个写入器线程从同一个队列中弹出,并将字符串写入驻留在 5400 rpm HDD RAID 阵列上的文件中。数据以大约 111 MBps 的速度推送,并以大约 80MBps 的速度弹出/写入。该程序的生存时间为 5600 秒,足以在队列中累积大约 176 GB 的数据。另一方面,我被限制在总共 64GB 的主内存。
我的问题是:我应该使用什么类型的队列?
这是我到目前为止所尝试的。
1) ArrayBlockingQueue
。这个有界队列的问题在于,无论数组的初始大小如何,一旦填满,我总是会遇到活性问题。事实上,程序启动几秒钟后,top
只报告一个活动线程。分析表明,平均而言,生产者线程大部分时间都在等待队列释放。这与我是否使用公平访问策略无关(构造函数中的第二个参数设置为 true)。
2) ConcurrentLinkedQueue
。就活跃度而言,这个无界队列表现更好。直到我用完内存,大约 700 秒后,所有 30 个生产者线程都处于活动状态。然而,当我超过 64GB 的限制后,事情变得异常缓慢。我猜这是因为分页问题,尽管我没有进行任何实验来证明这一点。
我预见到两种方法可以摆脱我的处境。
1) 购买固态硬盘。希望 I/O 速率的提高会有所帮助。
2)在写入文件之前压缩输出流。
有替代方案吗?我是否遗漏了上述任何一个队列的构造/使用方式?有没有更聪明的方法来使用它们?Java Concurrency in Practice 一书提出了一些饱和策略(第 8.3.3 节),以防有界队列填满的速度快于耗尽的速度,但不幸的是它们都没有——中止、调用者运行,并且两个丢弃政策---适用于我的场景。