Java - Thread-Sicherheit von ArrayList-Konstruktoren

8

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

    
andy boot 21.04.2010, 09:49
quelle

4 Antworten

4

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 .

    
Kevin Bourrillion 21.04.2010, 14:15
quelle
7
  

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.

    
Stephen C 21.04.2010 10:05
quelle
5

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.

    
Joe Daley 21.04.2010 10:13
quelle
1

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.

>     
Eyal Schneider 21.04.2010 10:12
quelle

Tags und Links