In Java, muss ich meine Sammlung synchronisiert erklären, wenn es nur schreib wird?
-
02-07-2019 - |
Frage
Ich fülle eine Sammlung ein einziges Mal, als mein J2EE Webapp beginnt. Dann mehrere Gewinde es zur gleichen Zeit zugreifen können, aber nur, es zu lesen.
Ich weiß, unter Verwendung einer synchronisierten Sammlung obligatorisch ist für Parallelen zu schreiben, aber ich brauche es noch Parallelen lesen?
Lösung
Normalerweise nein, weil Sie ändern nicht den internen Zustand der Sammlung in diesem Fall. Wenn Sie über die Auflistung durchlaufen eine neue Instanz des Iterator erstellt wird und der Zustand der Iteration pro Iterator-Instanz.
Abgesehen beachten Sie: Denken Sie daran, dass eine Nur-Lese-Sammlung, indem Sie nur verhindern Änderungen an der Sammlung selbst. Jedes Sammelelement ist noch veränderbar.
class Test {
public Test(final int a, final int b) {
this.a = a;
this.b = b;
}
public int a;
public int b;
}
public class Main {
public static void main(String[] args) throws Exception {
List<Test> values = new ArrayList<Test>(2);
values.add(new Test(1, 2));
values.add(new Test(3, 4));
List<Test> readOnly = Collections.unmodifiableList(values);
for (Test t : readOnly) {
t.a = 5;
}
for (Test t : values) {
System.out.println(t.a);
}
}
}
Diese Ausgänge:
5
5
Wichtige Überlegungen von @WMR answser.
Es hängt davon ab, ob die Fäden, die Ihre Sammlung zu lesen gestartet vor oder nachdem Sie es sind zu füllen. Wenn sie begann, bevor Sie es zu füllen, Sie haben keine Garantien (ohne Synchronisieren), dass diese Fäden jemals die aktualisierten Werte sehen.
Der Grund hierfür ist die Java Memory Modell, wenn Sie wissen wollen, lesen Sie mehr die Abschnitt „Sichtbarkeit“ unter diesem Link: http://gee.cs.oswego.edu/dl/cpj/jmm. html
Und selbst wenn die Fäden gestartet nachdem Sie Ihre Sammlung füllen, Sie Möglicherweise müssen synchronisiert werden, weil Ihr Sammlung Umsetzung könnte sich ändern sein interner Zustand sogar auf Lese Operationen (Danke Michael Bar-Sinai , Ich wusste nicht, solche Sammlungen existierte).
Eine weitere sehr interessante Lektüre auf dem Thema der Parallelität, die umfasst Themen wie Veröffentlichung von Objekten, Sichtbarkeit usw. viel detaillierter Brian Goetz ist Buch Java rel="nofollow Concurrency in Praxis .
Andere Tipps
Es hängt davon ab, ob die Fäden, die Ihre Sammlung liest gerade gestartet werden, bevor oder nachdem Sie es sind zu füllen. Wenn sie gestartet sind, bevor Sie es füllen, haben Sie keine Garantie (ohne Synchronisation), dass diese Fäden werden immer die aktualisierten Werte sehen.
Der Grund hierfür ist das Java-Speichermodell, wenn Sie mehr wissen wollen unter diesem Link im Abschnitt „Sichtbarkeit“ lesen: http://gee.cs.oswego.edu/dl/cpj/jmm.html
Und selbst wenn die Fäden, nachdem Sie füllen Sie Ihre Sammlung begonnen werden, könnten Sie müssen synchronisiert werden, da Ihre Sammlung Implementierung seinen internen Zustand auch auf Leseoperationen verändern könnte (durch Michael Bar-Sinai , ich nicht solche Sammlungen wusste gab es in dem Standard-JDK).
Eine weitere sehr interessante Lektüre zum Thema Gleichzeitigkeit, die Themen wie Veröffentlichung von Objekten umfasst, Sichtbarkeit usw. viel detaillierter ist Brian Goetz Buch Java Concurrency in Practice .
Im allgemeinen Fall, sollten Sie. Dies liegt daran, einige Sammlungen ihre interne Struktur ändern während liest. Ein LinkedHashMap, die den Zugriff verwendet, um ein gutes Beispiel. Aber nicht nur mein Wort für es:
Zugriff geordneten verknüpften Hash-Karten, nur die Karte mit get Abfrage ist eine strukturelle Modifikation Die verlinkte Hash-Karte javadoc
Wenn Sie absolut sicher sind, dass es keine Caches, keine Sammlung Statistiken, keine Optimierungen, kein lustiges Zeug überhaupt - Sie müssen nicht synchronisiert werden müssen. In diesem Fall würde ich eine Art Einschränkung für die Sammlung zu setzen haben: Sie erklären nicht die Sammlung als Karte (die LinkedHashMap erlauben würde), sondern als HashMap (für die Puristen, eine endgültige Unterklasse von HashMap, aber das könnte es zu nehmen weit ...).
Sie müssen nicht, wie in anderen Antworten erklärt. Wenn Sie sicherstellen möchten, dass Ihre Sammlung nur gelesen wird, können Sie:
yourCollection = Collections.unmodifableCollection(yourCollection);
(ähnliches Verfahren existiert für List, Set, Karten und andere Sammlungstypen)
Die Sammlung selbst nicht, aber denken Sie daran, dass wenn das, was hält es auch nicht unveränderlich ist, diese separaten Klassen ihre eigene Synchronisation benötigen.