Ich bin nicht sicher, ich verstehe die Frage, aber es scheint es einen Logikfehler für einen Thread T1 darstellen würde, die nur die Verarbeitung ist, für Beispiel: Datensätze, die mit AA beginnen, um die gesamte Datei als "Parsed" zu markieren? Was passiert, wenn Ihre Anwendung beispielsweise nach T1-Aktualisierungen abstürzt, während T2 jedoch BB-Datensätze verarbeitet? Einige BB-Datensätze sind wahrscheinlich verloren, richtig?
Wie auch immer, der Kern des Problems ist, dass Sie eine Race Condition mit zwei Threads haben, die das gleiche Objekt aktualisieren. Die Ausnahme für veraltete Objekte bedeutet nur, dass einer Ihrer Threads das Rennen verloren hat. Eine bessere Lösung vermeidet ein Rennen vollständig.
(Ich gehe hier davon aus, dass die individuelle Datensatzverarbeitung idempotent ist, wenn das nicht der Fall ist, haben Sie größere Probleme, da einige Fehlermodi zu einer erneuten Verarbeitung von Datensätzen führen. Wenn die Datensatzverarbeitung nur einmal ausgeführt werden muss einmal, dann haben Sie ein schwierigeres Problem, für das eine Nachrichtenwarteschlange wahrscheinlich eine bessere Lösung wäre.)
Ich würde die Funktionalität von java.util.concurrent verwenden, um Datensätze an Thread-Worker zu verteilen, und mit dem Thread interagieren zu lassen Ruhezustand blockieren, bis alle Datensätze verarbeitet wurden. Zu diesem Zeitpunkt kann dieser Thread die Datei als "Parsed" markieren.
Zum Beispiel
// do something like this during initialization, or use a Guava LoadingCache...
Map<RecordType, Executor> executors = new HashMap<>();
// note I'm assuming RecordType looks like an enum
executors.put(RecordType.AA_RECORD, Executors.newSingleThreadExecutor());
dann, wie Sie die Datei bearbeiten, versenden Sie jeden Datensatz wie folgt, um eine Liste von Futures auf den Status der anstehenden Aufgaben entsprechenden Aufbau.Nehmen wir an, erfolgreich verarbeiten ein Datensatz einen boolean „true“ zurückgibt:
List<Future<Boolean>> tasks = new ArrayList<>();
for (Record record: file.getRecords()) {
Executor executorForRecord = executors.get(record.getRecordType());
tasks.add(executor.submit(new RecordProcessor(record)));
}
Jetzt warten, bis alle Aufgaben erfolgreich abgeschlossen - es gibt elegantere Wege, dies zu tun, vor allem mit Guava. Beachten Sie, dass Sie hier auch mit ExecutionException umgehen müssen, wenn Ihre Aufgabe mit einer Ausnahme fehlgeschlagen ist. Ich beschönige das hier.
boolean allSuccess = true;
for (Future<Boolean> task: tasks) {
allSuccess = allSuccess && task.get();
if (!allSuccess) break;
}
// if all your tasks completed successfully, update the file record
if (allSuccess) {
file.setStatus("Parsed");
}
Sie haben also eine Flat-Datei und ein Rennen zwischen zwei Threads, um ein Feld zu aktualisieren, das bei Abschluss "geparst" wird? Also ist es erlaubt, bei einer Datei mit einem AA und einem agazillion BB, dass AA-Parsing in Millisekunden endet, das BB-Parsing "nie" endet und Ihr Status auf "geparst" gesetzt ist? Oder sollte es "teilweise geparst" und nur "vollständig geparst" werden, wenn sowohl AA als auch BB getan werden? –
Guter Punkt. In den meisten Fällen (99,99 ‰) möchten beide Threads den Status als geparst aktualisieren. Nicht zu viel Unterschied. AA sind Zahlungen .. BB sind Schecks. Nicht zu viel Unterschied in der Menge. Der Anfangsstatus wird empfangen und der Endstatus wird analysiert. Nein zwischen den Status. –
Sie können das Schlüsselwort 'synchronize' in Java verwenden, um gleichzeitige Threads zu verarbeiten. – Jodo1992