Atomare Variablen: Aktualisierungen ohne Locks
Verwenden Sie AtomicInteger, AtomicLong und AtomicReference für threadsichere Zähler ohne Locks.
Atomare Variablen: Aktualisierungen ohne Locks ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.
Das Problem mit nichtatomaren Operationen
Das einfache Inkrement count++ ist NICHT threadsicher — es besteht aus drei Operationen: Lesen, Addieren, Schreiben. Gleichzeitig ausgeführte Threads können diese Operationen verschachteln, wodurch Aktualisierungen verloren gehen. Atomare Variablen lösen dieses Problem ohne Sperren.
// UNSAFE:
int count = 0;
// Thread A reads count=0, Thread B reads count=0
// Both write 1 — second update lost!
count++; // NOT thread-safe
// SAFE:
import java.util.concurrent.atomic.*;
AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet(); // atomic, lock-freeGrundlagen von AtomicInteger
AtomicInteger stellt Integer-Operationen bereit, die mithilfe von Compare-and-Swap-Anweisungen (CAS) der CPU garantiert atomar sind — Sperren werden nicht benötigt.
AtomicInteger counter = new AtomicInteger(0);
counter.set(10); // set to 10
System.out.println(counter.get()); // 10
int prev = counter.getAndIncrement(); // returns 10, sets to 11
int curr = counter.incrementAndGet(); // sets to 12, returns 12
counter.addAndGet(5); // adds 5, returns 17
counter.decrementAndGet(); // subtracts 1, returns 16compareAndSet: Die CAS-Operation
compareAndSet(expected, update) aktualisiert den Wert nur dann atomar, wenn er aktuell dem erwarteten Wert entspricht. Die Methode gibt true zurück, wenn die Aktualisierung erfolgreich war. Dies bildet die Grundlage aller sperrenfreien Algorithmen.
AtomicInteger ai = new AtomicInteger(5);
boolean updated = ai.compareAndSet(5, 10); // current==5? set to 10
System.out.println(updated); // true
System.out.println(ai.get()); // 10
boolean failed = ai.compareAndSet(5, 20); // current==10, not 5 → fails
System.out.println(failed); // false
System.out.println(ai.get()); // still 10AtomicLong für Zähler
AtomicLong ist das entsprechende 64-Bit-Pendant. Es wird häufig für Sequenzgeneratoren und Trefferzähler verwendet:
AtomicLong seq = new AtomicLong(0);
// Thread-safe sequence generator:
long nextId() {
return seq.incrementAndGet();
}
System.out.println(nextId()); // 1
System.out.println(nextId()); // 2
System.out.println(nextId()); // 3AtomicBoolean
Threadsicheres boolesches Flag. Wird häufig für eine einmalige Initialisierung oder Signale zum Herunterfahren verwendet:
AtomicBoolean initialized = new AtomicBoolean(false);
void initOnce() {
// compareAndSet: only first caller succeeds
if (initialized.compareAndSet(false, true)) {
System.out.println("Initializing...");
// perform expensive init
} else {
System.out.println("Already initialized");
}
}AtomicReference
AtomicReference<V> stellt atomare Aktualisierungen einer Objektreferenz bereit. Es wird zur Implementierung sperrenfreier Datenstrukturen verwendet:
import java.util.concurrent.atomic.*;
record Config(String host, int port) {}
AtomicReference<Config> configRef =
new AtomicReference<>(new Config("localhost", 8080));
// Hot-swap the configuration atomically:
Config oldConfig = configRef.get();
Config newConfig = new Config("prod.example.com", 443);
boolean swapped = configRef.compareAndSet(oldConfig, newConfig);
System.out.println(swapped); // true
System.out.println(configRef.get()); // Config[host=prod.example.com, port=443]updateAndGet / getAndUpdate
Wenden Sie mithilfe einer intern verwendeten CAS-Wiederholungsschleife eine Funktion atomar an:
AtomicInteger value = new AtomicInteger(10);
// Apply function atomically: square the value
int newVal = value.updateAndGet(x -> x * x);
System.out.println(newVal); // 100
// Get old, then apply:
int old = value.getAndUpdate(x -> x + 1);
System.out.println(old); // 100
System.out.println(value.get()); // 101accumulateAndGet
Kombinieren Sie den aktuellen Wert mithilfe einer Funktion mit einem angegebenen Wert:
AtomicInteger max = new AtomicInteger(0);
// Keep running maximum:
max.accumulateAndGet(42, Math::max); // max(0, 42) = 42
max.accumulateAndGet(15, Math::max); // max(42, 15) = 42
max.accumulateAndGet(99, Math::max); // max(42, 99) = 99
System.out.println(max.get()); // 99LongAdder für Zähler mit hoher Konkurrenz
Bei hoher Konkurrenz zwischen Threads können die CAS-Wiederholungen von AtomicLong die Leistung beeinträchtigen. LongAdder verwendet mehrere Zellen, um die Konkurrenz zu verringern:
import java.util.concurrent.atomic.*;
LongAdder adder = new LongAdder();
// Multiple threads can call add() with minimal contention:
adder.increment();
adder.add(5);
adder.increment();
System.out.println(adder.sum()); // 7
// Note: sum() is NOT atomic with add() — use only when no concurrent addsAtomare Arrays
AtomicIntegerArray / AtomicLongArray stellen atomare Operationen für einzelne Array-Elemente bereit:
AtomicIntegerArray arr = new AtomicIntegerArray(5);
arr.set(0, 10);
arr.incrementAndGet(0);
arr.compareAndSet(2, 0, 42); // index 2: if 0, set 42
System.out.println(arr.get(0)); // 11
System.out.println(arr.get(2)); // 42Wann Sie Atomics statt Sperren verwenden sollten
Verwenden Sie atomare Variablen, wenn:
- Variablen einzeln aktualisiert werden (Zähler, Flags, Referenzen)
- nur geringe Konkurrenz vorliegt
- sperrenfreie Leistung wichtig ist
Verwenden Sie Sperren, wenn:
- mehrere Variablen atomar aktualisiert werden müssen
- komplexe bedingte Logik erforderlich ist
- sehr hohe Konkurrenz vorliegt (CAS-Wiederholungen beeinträchtigen die Leistung)
Kurzer Test
Was garantiert compareAndSet(expected, update)?
Zusammenfassung: Atomare Variablen
Wichtige Erkenntnisse:
- Atomare Typen verwenden CAS-Anweisungen der CPU — sie sind sperrenfrei und threadsicher
- AtomicInteger/Long/Boolean/Reference für Atomizität einzelner Variablen
- compareAndSet bildet die Grundlage sperrenfreier Algorithmen
- updateAndGet/accumulateAndGet für funktionale Aktualisierungen
- LongAdder für Zähler-Szenarien mit hoher Konkurrenz
Häufig gestellte Fragen
Ist die Lektion „Atomare Variablen: Aktualisierungen ohne Locks“ kostenlos?
Ja — der vollständige Text von „Atomare Variablen: Aktualisierungen ohne Locks“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Atomare Variablen: Aktualisierungen ohne Locks“?
Verwenden Sie AtomicInteger, AtomicLong und AtomicReference für threadsichere Zähler ohne Locks. Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Java Academy zu starten?
Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Atomare Variablen: Aktualisierungen ohne Locks“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?
Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- ReentrantLock vs. synchronized
- ReadWriteLock für Leser-Schreiber-Szenarien
- Atomare Variablen: Aktualisierungen ohne Locks
- StampedLock und optimistische Lesezugriffe