Was ist die Verwendung von Sammlungen.synchronizedList () - Methode? Es scheint nicht zu synchronisieren, die Liste
Ich versuche, fügen Sie String
Werten zu einer ArrayList
mit zwei threads. Was ich will, ist, dass während ein thread ist das hinzufügen der Werte, der andere thread sollte nicht stören, also habe ich die Collections.synchronizedList
Methode. Aber es scheint, dass, wenn ich nicht explizit synchronisieren auf ein Objekt hinzufügen, wird in einem nicht synchronisierte Weise.
Ohne ausdrückliche synchronisierten block:
public class SynTest {
public static void main(String []args){
final List<String> list=new ArrayList<String>();
final List<String> synList=Collections.synchronizedList(list);
final Object o=new Object();
Thread tOne=new Thread(new Runnable(){
@Override
public void run() {
//synchronized(o){
for(int i=0;i<100;i++){
System.out.println(synList.add("add one"+i)+ " one");
}
//}
}
});
Thread tTwo=new Thread(new Runnable(){
@Override
public void run() {
//synchronized(o){
for(int i=0;i<100;i++){
System.out.println(synList.add("add two"+i)+" two");
}
//}
}
});
tOne.start();
tTwo.start();
}
}
Die Ausgabe, die ich habe ist:
true one
true two
true one
true two
true one
true two
true two
true one
true one
true one...
Mit der ausdrücklichen synchronized-block auskommentiert, ich bin das stoppen der Einmischung aus dem anderen thread, die beim hinzufügen. Mal den thread erworben hat, die Sperre wird ausgeführt, bis es fertig ist.
Beispiel-Ausgabe nach dem einkommentieren der synchronisierte block:
true one
true one
true one
true one
true one
true one
true one
true one...
Also, warum ist das Collections.synchronizedList()
nicht tun, die Synchronisierung?
- was erwarten Sie? wiederholt
one two one two one two...
? Die Synchronisation ist auf der Liste Betrieb, nicht auf die threads - Blick in den code von SynchronizedList zu verstehen, wie der sync ist implementiert: grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einer synchronisierten Liste synchronisiert nur Methoden dieser Liste.
Bedeutet es, ein thread wird nicht in der Lage, ändern Sie die Liste, während ein anderer thread gerade läuft eine Methode aus dieser Liste. Das Objekt ist gesperrt während der Verarbeitung Methode.
Als ein Beispiel, sagen wir, zwei threads laufen
addAll
auf Ihrer Liste, mit 2 verschiedenen Listen (A=A1,A2,A3
,B=B1,B2,B3
) als parameter.Als die Methode synchronisiert ist, können Sie sicher sein, dass diese Listen nicht zusammengeführt werden, wie zufällig
A1,B1,A2,A3,B2,B3
Du nicht entscheiden, Wann ein thread übergabe der Prozess zu dem anderen thread. Jeder Methodenaufruf hat voll laufen und zurück, bevor die andere laufen konnte. So können Sie entweder bekommen
A1,A2,A3,B1,B2,B3
oderB1,B2,B3,A1,A2,A3
(Da wir nicht wissen, welche thread-Aufruf wird zuerst ausgeführt).In Ihrem ersten Stück code, beide threads läuft auf der gleichen Zeit. Und beide versuchen
add
ein element in die Liste ein. Sie haben keine Möglichkeit zu blockieren eines Threads außer die Synchronisation auf denadd
Methode, so dass nichts verhindern, dass thread 1 aus dem mehrereadd
Betrieb vor der übergabe der Prozess-thread-2. So Ihr Ausgang ist völlig normal.In Ihrem zweiten Teil des Codes (der eine unkommentierte), die Sie klar angeben, dass es einen thread komplett zu sperren, die Liste aus dem anderen thread vor dem Start der loop. Also, stellen Sie sicher, dass einer von deinem thread, der ausgeführt wird, volle Schleife, bevor die anderen könnte man auf die Liste.
Collections.synchronizedList()
synchronisieren werden alle Zugriffe auf die gesicherte Liste außer während der Iteration, die noch getan werden muss, um in einem synchronisierten block mit der synchronisierten Liste-Instanz als Objekt überwachen.So zum Beispiel, hier ist der code der
add
MethodeDies garantiert einen seriellen Zugriff auf die gesicherte Liste, also wenn Ihr 2 threads rufen
add
zur gleichen Zeit, ein thread eine Sperre bekommen, fügen Sie Ihr element und lassen Sie die Sperre dann der zweite thread wird in der Lage sein, die Sperre, und fügen Sie Ihr element, das ist, warum Sie bekommen alternativone
undtwo
in Ihrer Ausgabe.Wenn Sie die Auskommentierung der synchronized-block, der code wird dann
In diesem Fall den thread, könnte die Sperre auf
o
ersten ausführen wird die gesamtefor
Schleife, bevor die Freigabe der sperren (außer wenn eine Ausnahme geworfen wird), so dass der andere thread zu führen, den Inhalt der synchronisierten block, das ist, warum Sie bekommen100
mal hintereinanderone
odertwo
dann100
aufeinanderfolgenden mal den anderen Wert.Beobachtbare Verhalten ist absolut korrekt -
synchronized
Ansatz, demonstrieren Sie im code-Beispiel nicht das gleiche wiesynchronizedList
. Im ersten Fall synchronisieren Sie die gesamte for-Anweisung, so dass nur ein thread ausgeführt wird, es gleichzeitig. Im zweiten Fall synchromize collection-Methoden selbst - das ist es, wassynchronizedList
steht. So sicher sein, dassadd
Methode ist synchronisiert, nicht aber diefor
Methode!Entsprechend der vorangegangenen Antworten, die Sie brauchen, um synchronisieren Sie die
synList
aus access threadtOne
undtTwo
. In diesem Fall können Sie verwenden Sie das monitor-Muster bietet eine Sicherheits-Zugang - damit threads.Unten habe ich angepasst, Ihre Codes mit anderen teilen, die das selbe Problem haben. In diesem code habe ich nur die
synList
um den Zugriff in synchronisierter Weise. Beachten Sie, dass es nicht notwendig ist erstellen anderen Objekt zu gewährleisten, um den Zugang von synList.Als Ergänzung zu dieser Frage siehe das Buch Java Concurrency in der Praxis jcip Kapitel 4, dass die Gespräche über die monitor-design-Muster, die inspiriert ist von Hoare Arbeit
}