Es gibt eine ausgezeichnete Erklärung für dieses Problem von Andrei Pangin vom 07. April 2015. Es ist hier verfügbar , aber in russischer Sprache verfasst (ich empfehle, Codebeispiele trotzdem zu überprüfen - sie sind international). Das allgemeine Problem ist eine Sperre während der Klasseninitialisierung.
Hier sind einige Zitate aus dem Artikel:
Laut JLS verfügt jede Klasse über eine eindeutige Initialisierungssperre , die während der Initialisierung erfasst wird. Wenn ein anderer Thread während der Initialisierung versucht, auf diese Klasse zuzugreifen, wird sie für die Sperre blockiert, bis die Initialisierung abgeschlossen ist. Wenn Klassen gleichzeitig initialisiert werden, kann es zu einem Deadlock kommen.
Ich habe ein einfaches Programm geschrieben, das die Summe der ganzen Zahlen berechnet. Was soll es drucken?
public class StreamSum {
static final int SUM = IntStream.range(0, 100).parallel().reduce((n, m) -> n + m).getAsInt();
public static void main(String[] args) {
System.out.println(SUM);
}
}
Entfernen parallel()
oder ersetzen Sie nun Lambda durchInteger::sum
Call - was wird sich ändern?
Hier sehen wir wieder einen Deadlock [es gab einige Beispiele für Deadlocks in Klasseninitialisierern zuvor im Artikel]. Aufgrund der parallel()
Stream-Operationen werden in einem separaten Thread-Pool ausgeführt. Diese Threads versuchen, den Lambda-Body auszuführen, der als private static
Methode innerhalb der StreamSum
Klasse in Bytecode geschrieben ist . Diese Methode kann jedoch nicht vor Abschluss des statischen Klasseninitialisierers ausgeführt werden, der auf die Ergebnisse der Stream-Fertigstellung wartet.
Was noch umwerfender ist: Dieser Code funktioniert in verschiedenen Umgebungen unterschiedlich. Es funktioniert ordnungsgemäß auf einem einzelnen CPU-Computer und hängt höchstwahrscheinlich auf einem Multi-CPU-Computer. Dieser Unterschied ergibt sich aus der Implementierung des Fork-Join-Pools. Sie können dies selbst überprüfen, indem Sie den Parameter ändern-Djava.util.concurrent.ForkJoinPool.common.parallelism=N