この質問は、Java の最新バージョンに関するものです。
30 個のプロデューサー スレッドが文字列を抽象キューにプッシュします。1 つのライター スレッドが同じキューからポップし、5400 rpm HDD RAID アレイに存在するファイルに文字列を書き込みます。データは約 111 MBps の速度でプッシュされ、約 80 MBps の速度でポップ/書き込みされます。プログラムは 5600 秒間存続します。これは、約 176 GB のデータがキューに蓄積されるのに十分です。一方、私は合計 64 GB のメイン メモリに制限されています。
私の質問は次のとおりです。どのタイプのキューを使用すればよいですか?
これが私がこれまでに試したことです。
1) ArrayBlockingQueue
. このバインドされたキューの問題は、配列の初期サイズに関係なく、配列がいっぱいになるとすぐにライブネスの問題が発生することです。実際、プログラムの開始から数秒後に、top
アクティブなスレッドが 1 つだけ報告されます。プロファイリングにより、プロデューサー スレッドは平均して、ほとんどの時間をキューが解放されるのを待つことに費やしていることがわかります。これは、フェア アクセス ポリシー (コンストラクターの 2 番目の引数を true に設定) を使用するかどうかに関係ありません。
2) ConcurrentLinkedQueue
. liveness に関する限り、この無制限のキューはより優れたパフォーマンスを発揮します。約 700 秒後にメモリが不足するまで、30 個すべてのプロデューサー スレッドがアクティブになります。しかし、64GB の制限を超えると、信じられないほど遅くなります。これはページングの問題によるものだと推測しますが、これを証明する実験は行っていません。
私は自分の状況から抜け出す方法を 2 つ予見しています。
1) SSD を購入します。うまくいけば、I/O レートの増加が役に立ちます。
2) ファイルに書き込む前に出力ストリームを圧縮します。
代替手段はありますか?上記のキューのいずれかが構築/使用される方法に何か欠けていますか? それらを使用するより賢い方法はありますか?Java Concurrency in Practice book では、制限されたキューが使い果たされるよりも速くいっぱいになる場合に備えて、いくつかの飽和ポリシー (セクション 8.3.3) を提案していますが、残念ながらそれらのどれも --- 中止、呼び出し元の実行、および 2 つの破棄です。ポリシー---私のシナリオに適用されます。