Bei der Arbeit erhielt ich die folgende Beratung. "Wenn die Parallelverarbeitung mit Completable Future durchgeführt wird, wird der Wert möglicherweise nicht alle zehn bis hundert Mal korrekt zurückgegeben."
Notieren Sie sich die Antwort zu diesem Zeitpunkt.
Die Ausführungsumgebung ist
ist.
Es gibt die folgenden Prozesse. Informationen werden mithilfe von CompletableFuture parallel in summaryItem gespeichert. xxxAPI.search (number); ruft eine externe API auf, um Artikelinformationen abzurufen. Wo lauern die Käfer?
public List<Item> search(int length) {
//Variablen, die Suchergebnisse enthalten
List<Item> summaryItem = new ArrayList<>(length);
List<CompletableFuture<Void>> futures = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
final int number = i;
CompletableFuture<Void> f = CompletableFuture.runAsync(() -> {
//Rufen Sie Daten ab, indem Sie eine externe API aufrufen
Item item = xxxAPI.search(number);
summaryItem.add(item);
}, pool);
futures.add(f);
}
//Warten Sie, bis die gesamte Parallelverarbeitung abgeschlossen ist
CompletableFuture<Void> all =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[length]));
all.join();
return summaryItem;
}
Dies ist Teil der folgenden Verarbeitung.
summaryItem.add(item);
summaryItem ist java.util.ArrayList. ArrayList ist nicht threadsicher. ** ** ** Werfen wir einen Blick auf JavaDoc.
https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayList.html
** Diese Implementierung ist nicht synchronisiert. ** Wenn mehrere Threads parallel auf eine ArrayList-Instanz zugreifen und mindestens einer dieser Threads die Liste strukturell ändert, muss sie extern synchronisiert werden. Strukturelle Änderungen sind das Hinzufügen oder Entfernen eines oder mehrerer Elemente oder das explizite Ändern der Größe des zugrunde liegenden Arrays. Das Festlegen nur des Werts eines Elements ist keine strukturelle Änderung. Dies wird normalerweise durch Synchronisieren mit einigen Objekten erreicht, die die Liste auf natürliche Weise kapseln. Wenn ein solches Objekt nicht vorhanden ist, müssen Sie die Methode Collections.synchronizedList verwenden, um die Liste zu "umbrechen". Es wird empfohlen, dies zum Zeitpunkt der Erstellung zu tun, um zu verhindern, dass versehentlich auf die Liste zugegriffen wird, ohne synchronisiert zu werden.
Du hast es fest geschrieben.
Verwenden Sie eine thread-sichere Liste. Oder wechseln Sie zunächst zur thread-sicheren Verarbeitung. Wir antworteten mit einem Ansatz in Form von.
Das Paket "java.util.concurrent" hat eine gut synchronisierte Liste. Lassen Sie uns dies verwenden.
List<Item> summaryItem = new ArrayList<>(length);
Ändern Sie einfach den obigen Code wie unten und es wird normal funktionieren.
List<Item> summaryItem = new CopyOnWriteArrayList<>(length);
In einigen Fällen löst die Verwendung von "Collections.synchronizedList" das Problem. Wenn Sie jedoch einen Iterator verwenden, müssen Sie sich trotzdem selbst synchronisieren.
Zunächst sollten Sie den Wert im Format java.util.function.Supplier zurückgeben.
public List<Item> search(int length) {
//Paralleler Ausführungsprozess der Suche
List<CompletableFuture<Item>> futures = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
final int number = i;
CompletableFuture<Item> f = CompletableFuture.supplyAsync(() -> {
//Rufen Sie Daten ab, indem Sie eine externe API aufrufen
return xxxAPI.search(number);
}, pool);
futures.add(f);
}
//Sammlung von Suchergebnissen
try {
List<Item> summaryItem = new ArrayList<>();
for (CompletableFuture<Item> f : futures) {
summaryItem.add(f.get());
}
return summaryItem;
} catch (ExecutionException | InterruptedException ex) {
throw new RuntimeException(ex);//Ich habe es angemessen geschrieben.
}
}
Es passiert sehr zufällig und der Punkt ist, dass es schwierig ist, ein Problem zu finden, ohne die Java-API zu kennen. Der Testcode wird auch (grob) durchlaufen.
Ich denke, es ist nützlicher, eine Codeüberprüfung für diese Teile durchzuführen, als zu debuggen.
Sie können es wahrscheinlich nicht mit CheckStyle finden, aber ich glaube, Sie können das Problem mit einem statischen Code-Analyse-Tool finden. Ich werde in Zukunft danach suchen.
Recommended Posts