Frage

Ich habe einige Beispiele in Java gesehen, in denen sie einen Codeblock synchronisieren, um eine Variable zu ändern, während diese Variable ursprünglich als flüchtig deklariert war.Ich habe das in einem Beispiel einer Singleton-Klasse gesehen, in der sie die eindeutige Instanz als flüchtig deklariert und den Block synchronisiert haben, der diese Instanz initialisiert ...Meine Frage ist, warum wir es für volatil erklären, während wir es synchronisieren, warum wir beides tun müssen?Reicht das eine nicht für das andere??

public class someClass {
volatile static uniqueInstance = null;

public static someClass getInstance() {
        if(uniqueInstance == null) {
            synchronized(someClass.class) {
                if(uniqueInstance == null) {
                    uniqueInstance = new someClass();
                }
            }
        }
        return uniqueInstance;
    }

Dank im Voraus.

War es hilfreich?

Lösung

Synchronisation von selbst wäre in diesem Fall ausreichend, wenn der erste Überprüfen innerhalb des synchronisierten Blocks (aber nicht und ein Thread ist möglicherweise keine Änderungen, die möglicherweise nicht von einem anderen angezeigt werden, wenn die Variable nicht volatil war).Volatil allein wäre nicht genug, weil Sie mehr als einen Betrieb atomarisch durchführen müssen.Aber Vorsicht!Was Sie hier haben, ist ein so genanntes doppelt geprüftes Sperren - ein gemeinsames Idiom, das leider funktioniert nicht zuverlässig .Ich denke, das hat sich seit Java 1.6 geändert, aber auch diese Art von Code kann riskant sein.

bearbeiten : Wenn die Variable volatil ist, funktioniert dieser Code seit JDK 5 (nicht 6, wie ich früher geschrieben habe), aber es funktioniert nicht wie erwartet unter JDK 1.4 oder früher. .

Andere Tipps

Hierbei wird die doppelt geprüfte Verriegelung verwendet. Beachten Sie, dass die if(uniqueInstance == null) liegt nicht im synchronisierten Teil.

Wenn uniqueInstance nicht flüchtig ist, kann es mit einem teilweise erstellten Objekt „initialisiert“ werden, wobei Teile davon nur für den Thread sichtbar sind, der im ausgeführt wird synchronized Block.volatile macht dies in diesem Fall zu einer Alles-oder-Nichts-Operation.

Wenn Sie nicht über den synchronisierten Block verfügen, könnten am Ende zwei Threads gleichzeitig an diesem Punkt ankommen.

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here

Und Sie erstellen zwei SomeClass-Objekte, was den Zweck zunichte macht.

Streng genommen brauchen Sie volatile nicht, die Methode hätte sein können

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}

Dies erfordert jedoch die Synchronisierung und Serialisierung jedes Threads, der getInstance() ausführt.

Dieser Beitrag erklärt die Ideehinter volatil.

Es ist auch in der Samenarbeit angesprochen, Java-Parallelität in der Praxis .

Die Hauptidee ist, dass die Parallele nicht nur den Schutz des gemeinsamen Zustands, sondern auch die Sichtbarkeit dieses Zustands zwischen Threads beinhaltet: Hier kommt volatil in. (Dieser größere Vertrag wird durch das Java-Speichermodell )

Sie können die Synchronisierung durchführen, ohne den synchronisierten Block zu verwenden. Es ist nicht nötig, die volatile Variable darin zu verwenden ... Volatile aktualisiert die eine Variable vom Hauptspeicher. Synchronisiertes Update Alle gemeinsam genutzten Variablen, auf die aus dem Hauptspeicher zugegriffen wurden. Sie können es also entsprechend Ihrer Anforderung verwenden ..

meine zwei Cent hier

FRIST Eine schnelle Erklärung der Intuition dieses Codes generasacodicetagpre.

Der Grund, warum es einzigartig überprüft, ist doppelt mehr, dass der Aufruf des synchronisierten Blocks relativ langsamer wird.So genannte doppelt geprüfte Verriegelung.

Zweiter, der Grund, warum es synchron verwendet, ist leicht zu verstehen, es macht die beiden Operationen innerhalb des synchronisierten Blocks atomar.

Dauer Der flüchtige Modifikator sorgt dafür, dass alle Threads die gleiche Kopie sehen, sodass die allererste Überprüfung außerhalb des synchronisierten Blocks den Wert von einzigartiger Abstimmung auf eine Weise sehen wird, die "synchronisiert" ist. mit dem synchronisierten Block.Ohne den volatilen Modifikator kann ein Thread einzigartig einen Wert zuweisen, aber der andere Thread sieht es möglicherweise nicht durch den ersten Scheck an.(Obwohl der zweite Scheck es sehen wird)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top