Java Academy · Lektion

Atomära variabler: uppdateringar utan lås

Använd AtomicInteger, AtomicLong och AtomicReference för trådsäkra räknare utan lås.

Lektion 3 av 413 steg

Atomära variabler: uppdateringar utan lås är en gratis lektion i Java Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Java Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Java Academy innehåller totalt 4 lektioner.

Problemet med icke-atomiska operationer

Den enkla inkrementeringen count++ är INTE trådsäker — den består av tre operationer: läs, addera, skriv. Samtidiga trådar kan fläta in dessa operationer i varandra, vilket orsakar förlorade uppdateringar. Atomiska variabler löser detta utan lås.

// 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-free

Grunderna i AtomicInteger

AtomicInteger tillhandahåller heltalsoperationer som garanterat är atomiska med hjälp av CPU-instruktioner för compare-and-swap (CAS) — inga lås behövs.

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 16

compareAndSet: CAS-operationen

compareAndSet(expected, update) uppdaterar värdet atomiskt endast om det aktuella värdet är lika med det förväntade värdet. Returnerar true om det lyckas. Detta är grunden för alla låsfria algoritmer.

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 10

AtomicLong för räknare

AtomicLong är motsvarigheten för 64 bitar. Används ofta för sekvensgeneratorer och träffräknare:

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()); // 3

AtomicBoolean

Trådsäker boolesk flagga. Används ofta för initiering en gång eller som signal för avstängning:

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> tillhandahåller atomiska uppdateringar av en objektreferens. Används för att implementera låsfria datastrukturer:

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

Tillämpa en funktion atomiskt med hjälp av en intern CAS-loop som försöker igen:

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()); // 101

accumulateAndGet

Kombinera det aktuella värdet med ett angivet värde med hjälp av en funktion:

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()); // 99

LongAdder för räknare med hög konkurrens

Vid hög konkurrens mellan trådar kan AtomicLongs CAS-försök försämra prestandan. LongAdder använder flera celler för att minska konkurrensen:

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 adds

Atomiska arrayer

AtomicIntegerArray / AtomicLongArray tillhandahåller atomiska operationer på enskilda arrayelement:

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)); // 42

När atomiska variabler ska användas i stället för lås

Använd atomiska variabler när:

  • Enskilda variabler ska uppdateras (räknare, flaggor, referenser)
  • Konkurrensen är låg
  • Låsfri prestanda är viktig

Använd lås när:

  • Flera variabler måste uppdateras atomiskt
  • Komplex villkorslogik behövs
  • Konkurrensen är mycket hög (CAS-försök försämrar prestandan)

Snabbkontroll

Vad garanterar compareAndSet(expected, update)?

Sammanfattning: Atomiska variabler

Viktigaste punkterna:

  • Atomiska typer använder CPU-instruktioner för CAS — låsfria och trådsäkra
  • AtomicInteger/Long/Boolean/Reference för atomicitet hos enskilda variabler
  • compareAndSet är grunden för låsfria algoritmer
  • updateAndGet/accumulateAndGet för funktionella uppdateringar
  • LongAdder för räknarsituationer med hög konkurrens
Gratis att börja

Lär dig Java med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
104
Lektioner
374

Vanliga frågor

Är lektionen ”Atomära variabler: uppdateringar utan lås” gratis?

Ja – hela texten till ”Atomära variabler: uppdateringar utan lås” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Java Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Java Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Atomära variabler: uppdateringar utan lås”?

Använd AtomicInteger, AtomicLong och AtomicReference för trådsäkra räknare utan lås. Ni övar på Java Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Java Academy?

Du behöver inga förkunskaper. Utbildningen i Java Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Atomära variabler: uppdateringar utan lås”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Java Academy-lektionen?

Ja. Varje Java Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. ReentrantLock kontra synchronized
  2. ReadWriteLock för läsar- och skrivarscenarier
  3. Atomära variabler: uppdateringar utan lås
  4. StampedLock och optimistiska läsningar
← Tillbaka till Java Academy