Java Academy · Oppitunti

Atomiset muuttujat: lukituksettomat päivitykset

Käytä AtomicInteger-, AtomicLong- ja AtomicReference-tyyppejä säieturvallisiin laskureihin ilman lukituksia.

Oppitunti 3/413 vaihetta

Atomiset muuttujat: lukituksettomat päivitykset on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Ei-atomisten operaatioiden ongelma

Yksinkertainen kasvatus count++ ei ole säieturvallinen — se koostuu kolmesta operaatiosta: lue, lisää, kirjoita. Samanaikaiset säikeet voivat limittyä näiden välillä, mikä aiheuttaa päivitysten katoamista. Atomiset muuttujat ratkaisevat tämän ilman lukkoja.

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

AtomicIntegerin perusteet

AtomicInteger tarjoaa kokonaislukujen operaatioita, jotka ovat atomisia CPU:n compare-and-swap (CAS) -käskyjen avulla — lukkoja ei tarvita.

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-operaatio

compareAndSet(expected, update) päivittää arvon atomisesti vain, jos nykyinen arvo on odotetun arvon suuruinen. Se palauttaa arvon true, jos päivitys onnistuu. Tämä muodostaa kaikkien lukottomien algoritmien perustan.

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 laskureille

AtomicLong on 64-bittinen vastine. Sitä käytetään usein sekvenssigeneraattoreissa ja osumamäärien laskureissa:

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

Säieturvallinen totuusarvolippu. Sitä käytetään usein kertaluonteiseen alustamiseen tai sammutussignaaleihin:

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> tarjoaa atomiset päivitykset olio-viitteeseen. Sitä käytetään lukottomien tietorakenteiden toteuttamiseen:

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

Käyttäkää funktiota atomisesti sisäisesti toteutetun CAS-uudelleenyrityssilmukan avulla:

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

Yhdistäkää nykyinen arvo annettuun arvoon funktion avulla:

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 suuren kilpailun laskureille

Säikeiden välisen kilpailun ollessa suurta AtomicLongin CAS-uudelleenyritykset voivat heikentää suorituskykyä. LongAdder käyttää useita soluja kilpailun vähentämiseen:

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

Atomiset taulukot

AtomicIntegerArray / AtomicLongArray tarjoavat atomiset operaatiot yksittäisille taulukon alkioille:

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

Milloin atomisia muuttujia ja milloin lukkoja kannattaa käyttää

Käyttäkää atomisia muuttujia, kun:

  • Päivitetään yhtä muuttujaa (laskureita, lippuja tai viitteitä)
  • Kilpailua on vähän
  • Lukottoman suorituskyvyn merkitys on suuri

Käyttäkää lukkoja, kun:

  • Useita muuttujia on päivitettävä atomisesti
  • Tarvitaan monimutkaista ehdollista logiikkaa
  • Kilpailu on erittäin suurta (CAS-uudelleenyritykset heikentävät suorituskykyä)

Pikatarkistus

Mitä compareAndSet(expected, update) takaa?

Kertaus: atomiset muuttujat

Tärkeimmät opit:

  • Atomiset tyypit käyttävät CPU:n CAS-käskyjä — ne ovat lukottomia ja säieturvallisia
  • AtomicInteger/Long/Boolean/Reference yhden muuttujan atomisuuteen
  • compareAndSet muodostaa lukottomien algoritmien perustan
  • updateAndGet/accumulateAndGet funktionaalisiin päivityksiin
  • LongAdder suuren kilpailun laskuritilanteisiin
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Atomiset muuttujat: lukituksettomat päivitykset” ilmainen?

Kyllä – oppitunnin ”Atomiset muuttujat: lukituksettomat päivitykset” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Atomiset muuttujat: lukituksettomat päivitykset”?

Käytä AtomicInteger-, AtomicLong- ja AtomicReference-tyyppejä säieturvallisiin laskureihin ilman lukituksia. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Atomiset muuttujat: lukituksettomat päivitykset”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. ReentrantLock ja synchronized
  2. ReadWriteLock lukija-kirjoittaja-tilanteissa
  3. Atomiset muuttujat: lukituksettomat päivitykset
  4. StampedLock ja optimistiset luvut
← Takaisin: Java Academy