List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
list.add("message");
}
Wird der Block "synchronisiert (Liste) {}" hier wirklich benötigt?
Antworten:
Sie müssen nicht synchronisieren, wie Sie in Ihrem Beispiel angegeben haben. Sehr wichtig ist jedoch, dass Sie die Liste synchronisieren müssen, wenn Sie sie wiederholen (wie im Javadoc angegeben):
Es ist unbedingt erforderlich, dass der Benutzer die zurückgegebene Liste manuell synchronisiert, wenn er darüber iteriert:
List list = Collections.synchronizedList(new ArrayList()); ... synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
Es kommt auf den genauen Inhalt des synchronized
Blocks an:
Wenn der Block eine einzelne atomare Operation für die Liste ausführt (wie in Ihrem Beispiel), synchronized
ist die überflüssig.
Wenn der Block führt auf der Liste mehrere Operationen - und Bedürfnisse die Sperre für die Dauer der Verbindung Betrieb aufrecht zu erhalten - dann das synchronized
ist nicht überflüssig. Ein häufiges Beispiel hierfür ist das Durchlaufen der Liste.
Der zugrunde liegende Code für die Additionsmethode Collections.synchronizedList lautet:
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
In Ihrem Beispiel ist es also nicht erforderlich, eine Synchronisierung hinzuzufügen.
Es ist auch wichtig zu beachten, dass alle Methoden, die Iteratoren verwenden, z. B. Collections.sort (), ebenfalls in einem synchronisierten Block gekapselt werden müssen.
Lesen Sie dieses Oracle-Dokument
Es heißt "Es ist unbedingt erforderlich, dass der Benutzer die zurückgegebene Liste manuell synchronisiert, wenn er darüber iteriert."
Wie von anderen erwähnt, sind die synchronisierten Sammlungen threadsicher , aber die zusammengesetzten Aktionen für diese Sammlungen sind standardmäßig nicht garantiert threadsicher.
Laut JCIP können die üblichen zusammengesetzten Aktionen sein
Der synchronisierte Codeblock des OP ist keine zusammengesetzte Aktion, also kein Unterschied, ob er hinzugefügt wird oder nicht.
Nehmen wir das Beispiel von JCIP und ändern Sie es ein wenig, um zu verdeutlichen, warum es notwendig ist, die zusammengesetzten Aktionen mit Sperre zu schützen.
Es gibt zwei Methoden, die mit derselben Sammlung arbeiten list
, die von umbrochen wurdeCollections.synchronizedList
public Object getLast(List<String> list){
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
public void deleteLast(List<String> list){
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
Wenn Methoden getLast
und deleteLast
gleichzeitig von zwei verschiedenen Threads aufgerufen werden, können die folgenden Zwischenblätter auftreten und getLast
werden ausgelöst ArrayIndexOutOfBoundsException
. Angenommen, der Strom lastIndex
beträgt 10.
Thread A (deleteLast) ->
Thread B (getLast) entfernen --------------------> get
Der Faden A. remove
das Element vor dem get
Betrieb in Thread B. Somit noch der Thread B 10 , wie die Verwendung lastIndex
zu nennen list.get
Verfahren, wird es gleichzeitig Problem führen.