„Hallo, Amigo!“

„Hallo, Ellie!“

„Ich möchte Ihnen etwas über den flüchtigen Modifikator erzählen. Wissen Sie, was das ist?“

„Irgendwas mit Fäden zu tun. Ich weiß es nicht mehr genau.“

„Dann hören Sie zu. Hier sind einige technische Details für Sie:“

„Ein Computer verfügt über zwei Arten von Speicher: globalen (normalen) Speicher und in den Prozessor integrierten Speicher. Der integrierte Prozessorspeicher ist in Register unterteilt, einen Cache der ersten Ebene (L1), einen Cache der zweiten Ebene (L2) und drittes Niveau (L3).“

„Diese Speichertypen haben unterschiedliche Geschwindigkeiten. Der schnellste und kleinste Speicher sind die Register, dann der Prozessor-Cache (L1, L2, L3) und schließlich der globale Speicher (der langsamste).“

„Der globale Speicher und der Prozessor-Cache arbeiten mit völlig unterschiedlichen Geschwindigkeiten, sodass die Java-Maschine es jedem Thread ermöglicht, die am häufigsten verwendeten Variablen im lokalen Thread-Speicher (im Prozessor-Cache) zu speichern.“

„Kann dieser Prozess irgendwie kontrolliert werden?“

„Nicht wirklich. Die gesamte Arbeit wird von der Java-Maschine erledigt. Sie ist sehr intelligent, wenn es um die Optimierung der Leistung geht.“

„Aber deshalb erzähle ich Ihnen das. Es gibt ein kleines Problem. Wenn zwei Threads mit derselben Variablen arbeiten, kann jeder eine Kopie in seinem eigenen lokalen Cache speichern. Und dann ändert möglicherweise ein Thread die Variable, aber der zweite Möglicherweise wird die Änderung nicht angezeigt, da noch mit einer eigenen Kopie der Variablen gearbeitet wird.

„Nun, was kann man dann tun?“

„Die Ersteller von Java haben für diese Situation ein spezielles Schlüsselwort bereitgestellt: volatile. Wenn von verschiedenen Threads auf eine Variable zugegriffen wird, müssen Sie sie mit dem Modifikator volatile markieren, damit die Java-Maschine sie nicht in den Cache legt. Dies ist normalerweise so sieht aus:"

public volatile int count = 0;

„Oh, ich erinnere mich. Du hast das bereits erwähnt. Das weiß ich bereits.“

„Sicher tust du das. Aber du hast dich erst daran erinnert, als ich es dir gesagt habe.“

„Ähm, nun ja, ich habe es ein wenig vergessen.“

„Wiederholung ist die Mutter des Lernens!“

„Hier sind ein paar neue Fakten zum flüchtigen Modifikator. Der flüchtige Modifikator garantiert nur, dass die Variable sicher gelesen und geschrieben wird. Er garantiert nicht, dass sie sicher geändert wird.“

"Was ist der Unterschied?"

„Schauen Sie sich an, wie sich die Variable ändert:“

Code Was wirklich passiert: Beschreibung
count++
register = count;

register = register+1;

count = register;
Schritt 1:
Der Wert der Variablenanzahl wird vom globalen Speicher in ein Prozessorregister kopiert.

Schritt 2.
Im Prozessor wird die Registervariable um 1 erhöht.

Schritt 3.
Der Wert der Variablen wird vom Prozessor in den globalen Speicher kopiert.

„Wow! Also werden alle Variablen nur im Prozessor geändert?“

"Ja."

„Und die Werte werden hin und her kopiert: vom Speicher in den Prozessor und zurück?“

"Ja."

„Der flüchtige Modifikator garantiert, dass beim Zugriff auf die Variablenanzahl diese aus dem Speicher gelesen wird (Schritt 1). Und wenn ein Thread einen neuen Wert zuweisen möchte, befindet er sich auf jeden Fall im globalen Speicher (Schritt 3).“

„Aber die Java-Maschine garantiert nicht, dass zwischen den Schritten 1 und 3 kein Thread-Wechsel stattfindet.“

„Das Erhöhen der Variablen um 1 sind also tatsächlich drei Operationen?“

"Ja."

„Und wenn zwei Threads gleichzeitig count++ ausführen wollen, könnten sie sich dann gegenseitig stören?“

„Ja, schau es dir an:“

Thread 1 Thread 2 Ergebnis
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

„Sie können also auf die Variable zugreifen, aber es ist immer noch riskant, sie zu ändern?“

„Na ja, du kannst es ändern, sei einfach vorsichtig ☺“

"Wie?"

Synchronisiert  ist unser bester Freund.“

"Ich verstehe."