Meine Frage bezieht sich auf die Collection-Klasse "synchronizedList".
Javadocs sagen:
It is imperative that the user manually synchronize on the returned list when iterating over it:
Obwohl für andere Methoden keine manuelle Synchronisierung erforderlich ist. Ich habe mir den Quellcode der Collections-Klasse angesehen und gefunden shyncronization wurde bereits für alle Methoden wie add
gesorgt %Vor%aber nicht für die Iterator-Methode . Ich denke, dass die Iterator-Methode auch auf die gleiche Art und Weise mit der Synchronisation umgehen konnte wie oben beschrieben (es hätte die zusätzliche Arbeit vermieden, d. h. manuelle Synchronisation für Programmierer). da bin ich mir sicher muss ein konkreter Grund dafür sein, aber ich vermisse es?
%Vor%Eine Möglichkeit, die manuelle Synchronisierung von Programmer zu vermeiden
%Vor%Ich denke, dass die Iterator-Methode die Synchronisation auch auf die gleiche Weise wie die obige Methode behandelt haben könnte
Nein, konnte es absolut nicht.
Der Iterator hat keine Kontrolle darüber, was Ihr Code zwischen Aufrufen der einzelnen Methoden tut. Das ist der Punkt. Ihr Iterationscode ruft hasNext()
und next()
wiederholt auf, und die Synchronisation während dieser Aufrufe ist zwar möglich, aber irrelevant - wichtig ist, dass kein anderer Code versucht, die Liste über die gesamte Zeit zu ändern du wiederholst .
Stellen Sie sich eine Zeitleiste vor:
%Vor% Der Iterator kann nicht zwischen dem Ende des Aufrufs von next()
bei t = 2 und dem Aufruf von hasNext()
bei t = 10 synchronisieren. Also, wenn ein anderer Thread versucht (sagen wir mal), ein Objekt zur Liste bei t = 7 hinzuzufügen, wie soll der Iterator das verhindern?
Dies ist das allgemeine Problem bei synchronisierten Sammlungen: Jede einzelne Operation ist synchronisiert, während Sie normalerweise eine ganze Chunky-Operation synchronisieren möchten.
Wenn Sie nicht die gesamte Iteration synchronisieren, kann ein anderer Thread die Auflistung während der Iteration ändern, was zu einer ConccurentModificationException führt.
Außerdem ist der zurückgegebene Iterator nicht Thread-sicher.
Sie könnten das beheben, indem Sie den Iterator in eine SynchronizedIterator
einschließen, die jede Methode im Iterator sperrt, aber das würde auch nicht helfen - ein anderer Thread könnte die Sammlung zwischen zwei Iterationen noch ändern und alles abbrechen.
Dies ist einer der Gründe, warum die Methoden Collections.synchronized*()
völlig nutzlos sind.
Weitere Informationen zur ordnungsgemäßen threadsicheren Sammlung finden Sie unter in meinem Blog .
Wenn Sie die manuelle Serialisierung vermeiden möchten, müssen Sie eine Sammlung wie java.util.concurrent.CopyOnWriteArrayList
verwenden. Jedes Mal, wenn ein Objekt zur Liste hinzugefügt wird, wird die zugrunde liegende Datenstruktur kopiert, um eine Ausnahme für gleichzeitige Änderungen zu vermeiden.
Der Grund, warum Sie in Ihrem Beispiel die manuelle Serialisierung am Iterator benötigen, ist, dass der Iterator die gleiche interne Datenstruktur wie die Liste verwendet, aber unabhängige Objekte sind und Iterator und Liste von verschiedenen Threads zu jedem beliebigen Zeitpunkt aufgerufen werden können .
Ein anderer Ansatz wäre, eine lokale Kopie der Liste zu erstellen und über die Kopie zu iterieren.
Tags und Links java synchronization list collections java.util.concurrent