5

Java JDK 1.7 でバッチ プロセスを実行しています。RHEL、2.6.18-308.el5 #1 SMP を使用するシステムで実行されています。

このプロセスは、データベースからメタデータ オブジェクトのリストを取得します。このメタデータから、ファイルへのパスを抽出します。このファイルは、実際に存在する場合と存在しない場合があります。

このプロセスは ExecutorService ( Executors.newFixedThreadPool()) を使用して複数のスレッドを起動します。各スレッドは、そのファイルを読み取り、その入力ファイルが存在する場合は別のファイルを書き込み (結果をログに記録する)、ファイルが存在しない場合は何もしない (その結果のログを除く) プロセスを起動する Callable を実行します。

動作が不定であることがわかります。各ファイルの実際の存在は常に一定ですが、このプロセスを実行しても一貫した結果は得られません。通常は正しい結果が得られますが、実際には存在するいくつかのファイルが存在しない場合があります。同じプロセスをもう一度実行すると、以前に存在しなかったと言われているファイルが見つかります。

なぜこれが起こっているのでしょうか。より信頼できる別の方法はありますか? 他のスレッドがディレクトリを読み取ろうとしているときに、マルチスレッド プロセスでファイルを書き込んでいるのは間違いですか? 小さいスレッド プール (現在 30) は役に立ちますか?

更新: このシナリオでワーカー スレッドによって呼び出される UNIX プロセスの実際のコードは次のとおりです。

public int convertOutputFile(String inputFile, String outputFile)
throws IOException
{
    List<String> args = new LinkedList<String>();
    args.add("sox");
    args.add(inputFile);
    args.add(outputFile);
    args.addAll(2, this.outputArguments);
    args.addAll(1, this.inputArguments);
    long pStart = System.currentTimeMillis();
    int status = -1;
    Process soxProcess = new ProcessBuilder(args).start();

    try {
        // if we don't wait for the process to complete, player won't
        // find the converted file.
        status = soxProcess.waitFor();
        if (status == 0) {
            logger.debug(String.format("SoX conversion process took %d ms.",
                    System.currentTimeMillis() - pStart));
        } else {
            logger.error("SoX conversion process returned an error status of " + status);
        }
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return status;
}

更新#2:

java.io.File.exists() から java.nio.Files.exists() に切り替える実験を試みましたが、これにより信頼性が向上するようです。以前と同じように、約 10% の確率で発生していましたが、複数回の試行で失敗状態をまだ確認していません。したがって、nio バージョンが、基になるファイル システムの処理方法において何らかの形でより堅牢であるかどうかを知りたいと考えています。 この発見は後に誤りであることが証明されました。nio はここでは役に立ちません。

更新 #3: さらに調べてみると、まだ同じ障害状態が発生していることがわかりました。したがって、nio に切り替えることは万能薬ではありません。エグゼキュータ サービスのスレッド プール サイズを 1 に減らすことで、より良い結果が得られました。これはより信頼性が高いようであり、別のスレッドが同じディレクトリに書き込むプロセスを起動している間に、あるスレッドがディレクトリを読み取る可能性はありません。ディレクトリ。

まだ調査していないもう 1 つの可能性は、出力ファイルを入力ファイルとは別のディレクトリに置いた方がよいかどうかということです。コーディングが簡単だったので、それらを同じディレクトリに配置しましたが、出力ファイルの作成が入力ディレクトリのスキャンと同じディレクトリに影響するため、混乱を招く可能性があります。

更新 #4: 出力ファイルが入力ファイル (その存在がチェックされている) とは異なるディレクトリに書き込まれるように再コーディングしても、特に問題は解決しません。状況を改善する唯一の変更は、ExecutorService スレッド プール サイズを 1 にすることです。つまり、この操作をマルチスレッド化しないことです。

4

3 に答える 3

1

アプリケーションが適切にマルチスレッド化されている可能性がありますが、FileSystem にアクセスしているときは常に制限があります。あなたの場合、あまりにも多くのスレッドが同時にアクセスしているため、FS がファイル ハンドルを使い果たしていると思います。ファイル インスタンスは、exists()例外をスローしないため、それを伝える方法がないためfalse、ディレクトリが存在する場合でも単に を返します。

于 2016-01-06T22:55:51.297 に答える