Thread Safe - letzte lokale Methodenvariable, die an Threads weitergegeben wird?

8

Führt der folgende Code zu denselben Problemen, wenn die Variable 'commonSet' dieser Methode stattdessen ein Feld auf Klassenebene ist. Wenn es sich um ein Feld auf Klassenebene handelt, muss das Hinzufügen zum Set-Vorgang innerhalb eines synchronisierten Blocks erfolgen, da HashSet nicht Thread-sicher ist. Sollte ich das gleiche im folgenden Code tun, da mehrere Threads zum Satz hinzufügen oder sogar der aktuelle Thread fortfahren kann, den Satz zu verändern.

%Vor%

Der Verweis auf "commonSet" ist durch Verwendung von final gesperrt. Aber mehrere Threads, die darauf ausgeführt werden, können die Werte in der Gruppe immer noch beschädigen (sie können Duplikate enthalten?). Zweitens ist Verwirrung seit "commonSet" ia eine Methoden-Level-Variable - es ist der gleiche Verweis auf den Stapelspeicher der aufrufenden Methode (threadCreatorFunction) und Stapelspeicher der Lauf-Methoden - ist das korrekt?

Es gibt einige Fragen dazu:

Aber ich kann nicht sehen, wie sie sich auf den thread-sicheren Teil eines solchen Teilens / Passierens von Mutables konzentrieren.

    
haps10 06.08.2012, 07:41
quelle

6 Antworten

9

Nein, das ist absolut nicht threadsicher. Nur weil Sie es in einer letzten Variablen haben, bedeutet dies, dass beide Threads die gleiche Referenz sehen, was in Ordnung ist - aber das Objekt wird nicht verwendet Threadsicherer.

Entweder müssen Sie den Zugriff synchronisieren oder ConcurrentSkipListSet .

    
Jon Skeet 06.08.2012, 07:44
quelle
5

Ein interessantes Beispiel.

Der Verweis commonSet ist Thread-sicher und unveränderlich. Es ist auf dem Stapel für den ersten Thread und ein Feld Ihrer anonymen Runnable -Klasse. (Sie können dies in einem Debugger sehen)

Der Satz commonSet bezieht sich auf veränderbar und nicht threadsicher. Sie müssen synchronisiert oder eine Sperre verwenden, um es threadsicher zu machen. (Oder verwenden Sie stattdessen eine threadsichere Sammlung)

    
Peter Lawrey 06.08.2012 07:44
quelle
1

Ich denke, du verpasst ein Wort in deinem ersten Satz:

  

Wird der folgende Code die gleichen Probleme verursachen, wenn die Variable 'commonSet' dieser Methode ein ??? anstelle eines Klassenebenenfelds ist.

Ich denke, du bist ein wenig verwirrt. Die Gleichzeitigkeitsprobleme haben nichts damit zu tun, ob der Verweis auf Ihre veränderbare Datenstruktur als final deklariert wird oder nicht. Sie müssen den Verweis als final deklarieren, da Sie es in der anonymen inneren Klasse schließen Erklärung für Ihre Runnable . Wenn Sie tatsächlich mehrere Threads haben, die die Datenstruktur lesen / schreiben, müssen Sie entweder Sperren (Synchronisieren) verwenden oder eine gleichzeitige Datenstruktur wie java.util.concurrent.ConcurrentHashMap .

    
DaoWen 06.08.2012 07:50
quelle
1

Der commonSet wird von zwei Threads geteilt. Sie haben es als final deklariert und somit die Referenz unveränderlich gemacht (Sie können sie nicht neu zuweisen), aber die tatsächlichen Daten innerhalb des Sets sind immer noch änderbar. Angenommen, ein Thread fügt einige Daten ein und ein anderer Thread liest einige Daten aus. Immer wenn der erste Thread Daten einfügt, möchten Sie diesen Satz höchstwahrscheinlich sperren, sodass kein anderer Thread lesen kann, bis diese Daten geschrieben sind. Passiert das mit einem HashSet? Nicht wirklich.

    
Eugene 06.08.2012 08:35
quelle
0

Wie andere bereits bemerkt haben, verwechseln Sie einige Konzepte wie Finale und synchronisiert.

Ich denke, wenn Sie erklären, was Sie mit Ihrem Code erreichen wollen, wäre es viel einfacher, Ihnen zu helfen. Ich habe den Eindruck, dass dieses Code-Snippet eher ein Beispiel für den eigentlichen Code ist.

Einige Fragen: Warum ist der Satz in der Funktion definiert? Soll es unter Threads geteilt werden? Etwas, das mich verwirrt, ist, dass Sie zwei Threads mit der gleichen Instanz des ausführbaren

erstellen %Vor%     
pablochacin 06.08.2012 08:06
quelle
0

Unabhängig davon, ob commonset von single thread oder multiple verwendet wird, ist es nur die Referenz, die für finale Objekte unveränderlich ist (dh wenn sie einmal zugewiesen wurde, können Sie keine andere obj-Referenz erneut zuweisen), aber Sie können den Inhalt referenzieren .

Wenn es nicht endgültig wäre, hätte ein Thread es wieder initialisiert und die Referenz geändert %Code% In diesem Fall können diese zwei Threads zwei verschiedene Commonsets verwenden, was wahrscheinlich nicht das ist, was Sie wollen

    
srikanth yaradla 06.08.2012 08:14
quelle