it-swarm.com.de

Collections.synchronizedList und synchronisiert

List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
    list.add("message");
}

Ist der Block "synchronized (list) {}" hier wirklich nötig?

63
romsky

Sie müssen nicht synchronisieren, wie Sie es in Ihr Beispiel einfügen. Allerdings, sehr wichtig, müssen Sie die Liste synchronisieren, wenn Sie sie wiederholen (wie im Javadoc angegeben): 

Es ist zwingend erforderlich, dass der Benutzer die zurückgegebene .__-Datei manuell synchronisiert. Liste beim Durchlaufen:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());   
}
91
Sam Goldberg

Das hängt vom genauen Inhalt des synchronized-Blocks ab:

  1. Wenn der Block eine einzelne, atomare Operation in der Liste durchführt (wie in Ihrem Beispiel), ist synchronized überflüssig.

  2. Wenn der Block mehrere Operationen auf der Liste durchführt - und die Sperre für die Dauer der Verbundoperation aufrechterhalten muss -, ist synchronized nicht überflüssig. Ein häufiges Beispiel hierfür ist das Durchlaufen der Liste.

29
NPE

Der zugrunde liegende Code für die Add-Methode Collections.synchronizedList lautet:

public void add(int index, E element) {
    synchronized (mutex) {list.add(index, element);}
}

In Ihrem Beispiel müssen Sie also keine Synchronisation hinzufügen.

20
assylias

Beachten Sie auch, dass alle Methoden, die Iteratoren verwenden, zum Beispiel Collections.sort (), auch in einem synchronisierten Block eingeschlossen sein müssen.

16
jpegjpg

Lesen Sie dies Oracle Doc

Es heißt: "Es ist zwingend erforderlich, dass der Benutzer die manuell zurückgegebene Liste beim Iterieren manuell synchronisiert"

7
snan

Wie von anderen bereits erwähnt, sind die synchronisierten Auflistungen thread-safe , aber die zusammengesetzten Aktionen für diese Auflistungen sind nicht standardmäßig garantiert threadsicher. 

Laut JCIP können die häufigsten zusammengesetzten Aktionen sein 

  • iteration
  • navigation
  • put-If-Abwesenheit
  • check-then-act

Der synchronisierte Codeblock des OP ist keine zusammengesetzte Aktion, es ist also kein Unterschied, ob Sie ihn hinzufügen oder nicht.

Nehmen wir das Beispiel von JCIP und ändern Sie es ein wenig, um zu klären, warum es notwendig ist, die zusammengesetzten Aktionen mit Sperre zu schützen.

Es gibt zwei Methoden, die dieselbe Sammlung verwenden, list, die von Collections.synchronizedList umschlossen wird.

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 die Methoden getLast und deleteLast gleichzeitig von zwei verschiedenen Threads aufgerufen werden, können folgende Interleaves vorkommen und getLast löst ArrayIndexOutOfBoundsException aus. Es sei angenommen, dass der Strom lastIndex 10 ist. 

Thread A (deleteLast) -> entfernen
Thread B (getLast) --------------------> get 

Der Thread A remove das Element vor der get-Operation in Thread B. Wenn der Thread B weiterhin 10 als lastIndex verwendet, um die list.get-Methode aufzurufen, führt dies zu einem gleichzeitigen Problem. 

1
Gearon