ファイルに複数回 (100k+) 書き込みをしようとしていますが、書き込みは不安定なネットワーク経由で行われます。これを行うために、JavaExecutorService
を使用してスレッドを生成することを検討していますが、どの設定の組み合わせが次のことを適切に行うのかよくわかりません。
- 一度に1つの書き込みのみを許可します(もちろん順序は重要です)
- 書き込みが各書き込みを実行するのに十分な時間 (たとえば 5 秒) を許可し、その時点で保釈します。
- 書き込みが遅い場合は、Executor に書き込みをキューに集めて待機させます。
- スレッド キューが空になるまで、プログラム全体を終了させないでください。
- ライターごとにスレッドを分けます。つまり、まったく同じライターがこの関数に入っている場合は、それを独自のキューに入れます。別のライター ポインターが入ってきた場合は、独自のキューを指定します (別のライターを同じキューに入れる必要はありません)。
これは、エグゼキューター機能とメイン プログラムのオブジェクトの.wait()
andコマンドを組み合わせることで実現できると思います。.notify()
ただし、エグゼキューター API を正確に操作してこれを行う方法がよくわかりません。
これが私が得たものです:
private void writeToFileInSeperateThread(final PrintWriter writer, final String text) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Thread(new Runnable() {
public void run() {
writer.println(text);
}
})).get(5L, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
executor.shutdown();
}
そのメソッドは、1 つのプロセスで 10 万回以上呼び出されるため、ExcutorService
毎回新しいインスタンスを作成する必要があるのか、同じインスタンスを利用する必要があるのか わかりません。(同じものを利用しようとして、.newSingleThreadExecutor()
ディレクティブに関連していると思われる例外が発生し続けました。
Java 5 準拠を維持したいが、Java 6 は問題ない。Windows XP/7 で動作します。
更新: これは初期テストでうまくいったようです:
private class WriterStringPair {
public final PrintWriter writer;
public final String text;
public WriterStringPair(PrintWriter writer, String text) {
this.writer = writer;
this.text = text;
}
}
private void writeTextInSeperateThread(Writer writer, String text) {
try {
textQueue.offer(new WriterStringPair(writer, text), 300L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
errOut.println(e);
e.printStackTrace();
}
}
final BlockingQueue<WriterStringPair> textQueue = new ArrayBlockingQueue<WriterStringPair>(500);
private void setWritingThread() {
new Thread((new Runnable() {
public void run() {
WriterStringPair q;
while (!shutdown && !Thread.currentThread().isInterrupted()) {
try {
q = textQueue.poll(1L, TimeUnit.SECONDS);
if (q != null) {
q.writer.write(q.text + "\n");
q.writer.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
})).start();
}