Zpět na domů

Vlákna v Javě: architektura a synchronizace

Článek rozebírá zařízení vláken v Javě od hardwarové úrovně procesoru po JVM. Jsou popsány mechanismy synchronizace, problémy Race Condition, Deadlock, Livelock a asynchronní CompletableFuture pro efektivní vývoj.

Mnohovláknovost Java: od jader CPU po Deadlock
Advertisement 728x90

Architektura vláken a synchronizace v Javě: od procesoru po JVM

Javový kód se kompiluje do bajtového kódu, který JVM převádí na strojové instrukce procesoru. Každé jádro procesoru zpracovává instrukce sekvenčně: za jeden takt zpracuje jednoduchou operaci, například posun bitu v registru. Registry jsou supersnadné paměťové buňky pro ukládání čísel, adres a dat.

Moderní procesory využívají superskálární architekturu. Hyper-Threading umožňuje jednomu hardwarovému vláknu provádět 2–6 instrukcí za takt, čímž vytváří iluzi několika logických vláken na jádru díky rychlému přepínání kontextu.

Počet souběžně spuštěných vláken je omezen počtem jader. Vlákná sdílejí heap paměť, kde se ukládají objekty, zatímco každé vlákno má vlastní stack pro lokální proměnné a reference na objekty.

Google AdInline article slot

Race Condition a struktura paměti

Race Condition nastává, když několik vláken současně čte a modifikuje jeden objekt v heapu. Výsledek je nepředvídatelný: závisí na pořadí provedení operací „přečti-změň-zapiš“.

Lokálně kód často funguje správně bez zátěže, ale v produkci pod vícevláknovou zátěží se kolize projevují nepravidelně. Proces v OS alokuje společnou paměť; vlákna uvnitř procesu jsou lehké jednotky provádění, které soutěží o zdroje.

Mechanismy synchronizace: wait/notify a monitory

Každý objekt v Javě má vestavěný monitor (zámek). Blok synchronized zachytí monitor objektu a zajišťuje:

Google AdInline article slot
  • Mutual Exclusion: pouze jedno vlákno provádí kód uvnitř bloku.
  • Visibility: změny jsou viditelné pro jiná vlákna po opuštění bloku (s podporou volatile).

Monitor obsahuje:

  • Entry Set: frontu vláken čekajících na zachycení.
  • Wait Set: vlákna ve stavu čekání.

Metody wait(), notify(), notifyAll() fungují pouze uvnitř synchronized bloku stejného objektu, jinak vyhodí IllegalMonitorStateException.

  • wait(): přesune vlákno do Wait Set.
  • notify(): probudí libovolné vlákno (riziko ztraceného probuzení).
  • notifyAll(): probudí všechna vlákna (preferováno).

Statické synchronized metody blokují monitor třídy (Class), nekolidují s instančními metodami (this).

Google AdInline article slot

Pokročilé zámky: ReentrantLock a Semaphore

Pro flexibilní ovládání použijte java.util.concurrent.locks.ReentrantLock:

Lock lock = new ReentrantLock();
lock.lock();
try {
    // kritická sekce
} finally {
    lock.unlock();
}

Klíčové metody:

  • tryLock(): zachycení bez čekání (false při neúspěchu).
  • tryLock(timeout, unit): čekání s timeoutem.
  • lockInterruptibly(): přerušitelné zachycení.
  • new ReentrantLock(true): fair locking (podle FIFO, pomalejší).

Semaphore omezuje přístup:

Semaphore sem = new Semaphore(3); // 3 povolení
sem.acquire(); // zachycení
sem.release(); // uvolnění

Problémy vícevláknovosti: Deadlock a Livelock

Deadlock: cyklická závislost zámků. Vlákno A drží lock1, čeká na lock2; vlákno B naopak. Systém zamrzne.

Vyhněte se:

  • Blokujte v pevném pořadí.
  • Používejte timeouty.
  • Minimalizujte vnořené zámky.

Livelock: vlákna jsou aktivní, ale nepostupují. Příklad: dvě vlákna se navzájem ustupují v cyklu, zatěžují CPU bez pokroku.

Synchronní vs asynchronní zpracování ve vláknech

Synchronní metoda blokuje vlákno na I/O (např. dotaz do DB): vlákno nečinně čeká na odpověď.

Asynchronní využívá CompletableFuture – kontejner pro odložený výsledek (pending, completed, failed).

Řetězce operací:

  • thenApply(): transformace výsledku.
  • thenCompose(): kompozice s jiným Future.
  • thenAccept(): spotřeba bez návratu.
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "result")
    .thenApply(s -> s.toUpperCase())
    .thenAccept(System.out::println);

Tím se vlákno uvolní pro jiné úlohy, což zvyšuje propustnost v vícevláknovém prostředí.

Klíčové body

  • Každé jádro provádí jedno hardwarové vlákno; Hyper-Threading emuluje vícenásobnost.
  • Race Condition z sdíleného heapu; synchronizace zajišťuje mutual exclusion a visibility.
  • notifyAll() je lepší než notify() kvůli riziku ztraceného probuzení.
  • ReentrantLock rozšiřuje synchronized: timeouty, přerušení, fair locking.
  • CompletableFuture buduje asynchronní potrubí bez blokování vláken.

— Editorial Team

Advertisement 728x90

Číst dál