Ich sehe mir diesen Code an. Dieser Konstruktor delegiert an die native Methode "System.arraycopy"
Ist es Thread sicher? Und damit meine ich, kann es jemals eine ConcurrentModificationException auslösen?
%Vor%Macht es einen Unterschied, ob die kopierte Sammlung ThreadSafe ist, zB eine CopyOnWriteArrayList?
%Vor%Bearbeiten: Ich bin mir bewusst, dass ThreadSafe! = ConcurrentModificationException. Ich versuche zu einem Zeitpunkt eine Momentaufnahme der Daten zu machen. Wenn also ein anderer Thread in der Mitte der Kopie auf someCollection schreibt, ist es mir egal, ob das Ergebnis das neue Objekt hat oder nicht. Ich will nur nicht, dass es eine ConcurrentModificationException wirft oder schlimmer
Ihre Frage ist, ob Sie sicher eine Momentaufnahme einer Sammlung erstellen können, die möglicherweise gleichzeitig von einem anderen Thread bearbeitet wird, indem Sie new ArrayList<Foo>(thatCollection)
verwenden. Die Antwort ist: Solange thatCollection
selbst Thread-sicher ist, ja. Wenn es also ein CopyOnWriteArrayList
, synchronizedList
oder Vector
ist, wenn es nicht Thread-sicher ist, zum Beispiel, wenn es ein anderes ArrayList
ist, geht es dir nicht gut. (Was passieren wird, könnte schlimmer sein als ein ConcurrentModificationException
.)
Der Grund dafür ist, dass der Konstruktor ArrayList
nur einen einzigen atomaren Aufruf an die andere Sammlung macht - an die Methode toArray
. Es geniesst also grundsätzlich die Sicherheit, die die Methode an sich hat. Es wurde nicht immer so implementiert, sondern nur aus diesem Grund. Wir machen dasselbe in Guava mit ImmutableList.copyOf
.
Dieser Konstruktor delegiert an die native Methode "System.arraycopy"
Tatsächlich ruft es toArray()
auf someCollection
auf. Das wird schließlich System.arraycopy
aufrufen, wenn someCollection
ein ArrayList
ist. Für andere Sammlungstypen wird das Array auf andere Arten erstellt.
Ist es Thread sicher?
Nein.
Und damit meine ich, kann es jemals eine ConcurrentModificationException auslösen?
Wenn es ein ArrayList
ist, wird es nicht ConcurrentModificationException
... werfen, aber das macht es nicht threadsicher !!
Wenn beispielsweise ein anderer Thread set(obj, pos)
auf someCollection
aufruft, während Ihr Thread diesen Konstruktor aufruft, ist der Inhalt Ihres neu erstellten ArrayList
unvorhersehbar.
Thread safe und ConcurrentModificationException sind unterschiedliche Konzepte. Ein threadsicheres Objekt ist ein Objekt, bei dem mehrere Threads gleichzeitig die Methoden aufrufen können und die im Objekt enthaltenen Daten garantiert nicht beschädigt werden (Beispiel: Ссылка ). Eine ConcurrentModificationException tritt auf, wenn Sie sich beispielsweise gerade in einer Sammlung befinden und die Auflistung ändert. Die Änderung könnte von einem anderen Thread oder demselben Thread stammen.
Wenn in Ihrem Konstruktor ein anderer Thread das someCollection
ändert, während Ihr Konstruktor es kopiert, kann dies zu undefiniertem Verhalten (dh Datenbeschädigung in Ihrer neuen Sammlung, weil die Sammlungen nicht threadsicher sind) oder zu einer ConcurrentModificationException führen (Wenn die Sammlung die gleichzeitige Änderung erkennt, ist dies nicht garantiert, da sie nicht threadsicher ist ...: -)
Wenn Ihr Konstruktor ein Collection<Object>
übernimmt, müssen Sie sicherstellen, dass andere Threads die Sammlung erst ändern, nachdem der Konstruktor zurückgegeben wurde.
Andererseits ist eine CopyOnWriteArrayList threadsicher und garantiert, dass keine ConcurrentModificationException ausgelöst wird. Sie sollten also auf diese Weise sicher sein, ohne zusätzlichen Synchronisationscode zu schreiben.
ConcurrentModificationException ist nicht das einzige Anzeichen dafür, dass etwas nicht threadsicher ist. Wenn zum Beispiel in Methode # 1 someCollection auch eine ArrayList ist, haben Sie nie eine ConcurrentModificationException (siehe Code). Die Datenintegrität ist jedoch gefährdet - wenn die Quell-ArrayListe während des Kopierens geändert wird, können sich nur einige der Änderungen in der Kopie widerspiegeln (und nicht unbedingt die ältesten Änderungen!).
Mit anderen Worten, die Atomarität ist nicht garantiert (es sei denn, die Quelle wurde speziell dafür entworfen, wie zum Beispiel mit CopyOnWriteArrayList).
BEARBEITEN: Wenn Sie tatsächlich davon ausgehen, dass Sie Ihre Threads nicht richtig synchronisieren, kopieren Sie ein Array mit einem Thread, während ein anderer Thread Referenzen aktualisiert. Dies ist im Java Memory Model problematisch und kann theoretisch zu unvorhersehbarem Verhalten führen.
>Tags und Links java concurrency collections