Warum verhält sich File.exists () in einer Multithread-Umgebung uneinheitlich?

Ich habe einen Batch-Prozess, der unter Java JDK 1.7 ausgeführt wird. Es läuft auf einem System mit RHEL, 2.6.18-308.el5 # 1 SMP.

Dieser Prozess ruft eine Liste von Metadatenobjekten aus einer Datenbank ab. Aus diesen Metadaten wird ein Pfad zu einer Datei extrahiert. Diese Datei kann vorhanden sein oder auch nicht.

Der Prozess verwendet den ExecutorService Executors.newFixedThreadPool()), um mehrere Threads zu starten. Jeder Thread führt ein Callable aus, das einen Prozess startet, der diese Datei liest und eine andere Datei schreibt, wenn diese Eingabedatei vorhanden ist (und das Ergebnis protokolliert), und nichts tut, wenn die Datei nicht vorhanden ist (außer das Ergebnis protokolliert).

Ich finde das Verhalten ist unbestimmt. Obwohl die tatsächliche Existenz der einzelnen Dateien durchgehend konstant ist, führt die Ausführung dieses Prozesses nicht zu konsistenten Ergebnissen. Es gibt normalerweise korrekte Ergebnisse, stellt jedoch gelegentlich fest, dass einige Dateien, die wirklich existieren, nicht vorhanden sind. Wenn ich denselben Vorgang erneut ausführe, werden die Dateien gefunden, von denen zuvor gesagt wurde, dass sie nicht vorhanden sind.

Warum könnte dies passieren, und gibt es eine Alternative, die zuverlässiger wäre? Ist es ein Fehler, Dateien in einem Multithread-Prozess zu schreiben, während andere Threads versuchen, das Verzeichnis zu lesen? Wäre ein kleinerer Thread-Pool hilfreich (derzeit 30)?

AKTUALISIEREN Hier ist der tatsächliche Code des Unix-Prozesses, der von den Worker-Threads in diesem Szenario aufgerufen wird:

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;
}

UPDATE # 2:

Ich habe versucht, von java.io.File.exists () auf java.nio.Files.exists () umzuschalten. Dies scheint für mehr Zuverlässigkeit zu sorgen. Ich habe den Fehlerzustand über mehrere Versuche hinweg noch nicht gesehen, wobei er nach wie vor in etwa 10% der Fälle auftrat. Ich schätze, ich möchte wissen, ob die nio-Version in Bezug auf den Umgang mit dem zugrunde liegenden Dateisystem robuster ist.Diese Feststellung wurde später als falsch erwiesen. nio ist hier keine hilfe.

UPDATE # 3: Bei weiterer Überprüfung finde ich immer noch den gleichen Fehlerzustand. Ein Wechsel zu nio ist also kein Allheilmittel. Ich habe bessere Ergebnisse erzielt, indem ich die Thread-Pool-Größe des Executor-Dienstes auf 1 reduziert habe. Dies scheint zuverlässiger zu sein, und auf diese Weise besteht keine Chance, dass ein Thread das Verzeichnis liest, während ein anderer Thread einen Prozess startet, der in dasselbe schreibt Verzeichnis

Eine weitere Möglichkeit, die ich noch nicht untersucht habe, ist, ob ich besser bedient werden könnte, wenn ich meine Ausgabedateien in ein anderes Verzeichnis als die Eingabedateien lege. Ich habe sie in dasselbe Verzeichnis gestellt, weil es einfacher zu codieren war, aber das kann verwirrend sein, da sich die Erstellung der Ausgabedatei auf dasselbe Verzeichnis auswirkt wie die Überprüfung des Eingabeverzeichnisses.

UPDATE # 4: Eine Neukodierung, damit die Ausgabedateien in ein anderes Verzeichnis als die Eingabedateien geschrieben werden (auf deren Existenz geprüft wird), hilft nicht besonders.Die einzige Änderung, die Abhilfe schafft, ist eine ExecutorService-Thread-Pool-Größe von 1, dh, diese Operation wird nicht mit mehreren Threads ausgeführt.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage