Vícevláknové aplikace

Proč to potřebuji?

Vícevláknové programování umožňuje provádět více úloh současně, což je nezbytné pro responzivní GUI aplikace, servery a efektivní využití vícejádrových procesorů. Správná synchronizace je klíčová pro předcházení chybám.

Teorie

Vlákno (thread) = nejmenší jednotka provádění v rámci procesu. Vlákna sdílejí paměť procesu, což přináší výkon i rizika (race conditions).

Vytvoření: rozšíření Thread nebo implementace Runnable. Moderní přístup: ExecutorService.

Synchronizace: synchronized blok/metoda zamkne přístup pro ostatní vlákna. Prevence race conditions.

Příklady

import java.util.concurrent.*;

// === Způsob 1: Runnable ===
Runnable uloha = () -> {
    for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName() + ": " + i);
        try { Thread.sleep(100); } catch (InterruptedException e) { break; }
    }
};

Thread t1 = new Thread(uloha, "Vlákno-1");
Thread t2 = new Thread(uloha, "Vlákno-2");
t1.start(); // spuštění vlákna
t2.start();
t1.join();  // čekání na dokončení
t2.join();

// === Synchronizace – sdílený čítač ===
class BezpecnyCitac {
    private int hodnota = 0;

    // synchronized metoda – jen jedno vlákno najednou
    public synchronized void zvys() {
        hodnota++;
    }

    public synchronized int getHodnota() {
        return hodnota;
    }
}

// Bez synchronized: race condition – výsledek je nepředvídatelný
// Se synchronized: vždy správný výsledek

// === ExecutorService – moderní přístup ===
ExecutorService executor = Executors.newFixedThreadPool(3);

// Odeslání úloh
Future<Integer> vysledek = executor.submit(() -> {
    Thread.sleep(1000);
    return 42;
});

executor.execute(() -> System.out.println("Běží na poolu"));

// Získání výsledku (blokující)
int hodnota = vysledek.get(); // čeká na dokončení, vrátí 42

// Ukončení poolu
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);

// === Synchronized blok (jemnější zamykání) ===
class Sklad {
    private final List<String> polozky = new ArrayList<>();
    private final Object zamek = new Object();

    public void pridej(String polozka) {
        synchronized (zamek) {
            polozky.add(polozka);
        }
    }

    public String odeber() {
        synchronized (zamek) {
            if (polozky.isEmpty()) return null;
            return polozky.remove(0);
        }
    }
}

Shrnutí

Klíčové body

  • Thread / Runnable – vytvoření vlákna, start() – spuštění
  • synchronized – zamezí souběžnému přístupu (prevence race condition)
  • ExecutorService – pool vláken, Future pro návratovou hodnotu
  • join() – čekání na dokončení vlákna