Sobes.tech
Middle

Pověz o závodní podmínce (race condition) a jak ji lze zabránit v vícevláknových aplikacích.

sobes.tech AI

Odpověď od AI

Stav závodu je chyba návrhu vícevláknového systému, kdy výsledek provádění programu závisí na pořadí, ve kterém různé vlákna vykonávají části kódu. K tomu dochází, když více vláken současně přistupuje ke sdílenému měnitelného zdroje bez řádné synchronizace.

Pro zabránění stavu závodu v Javě se používají následující přístupy:

  1. Použití synchronizovaných metod a bloků:

    class Counter {
        private int count = 0;
    
        // Synchronizovaná metoda
        public synchronized void increment() {
            count++;
        }
    
        // Synchronizovaný blok
        public void decrement() {
            synchronized (this) {
                count--;
            }
        }
    }
    

    Klíčové slovo synchronized zajišťuje, že pouze jedno vlákno může současně vykonávat synchronizovaný kód pro daný objekt (nebo třídu, pokud je metoda statická).

  2. Použití třídy Lock z balíčku java.util.concurrent.locks:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class SafeCounter {
        private int count = 0;
        private final Lock lock = new ReentrantLock();
    
        public void increment() {
            lock.lock(); // Získání zámku
            try {
                count++;
            } finally {
                lock.unlock(); // Uvolnění zámku
            }
        }
    }
    

    Lock poskytuje flexibilnější mechanismy zámků ve srovnání se synchronized.

  3. Použití atomických proměnných z balíčku java.util.concurrent.atomic:

    import java.util.concurrent.atomic.AtomicInteger;
    
    class AtomicCounter {
        private AtomicInteger count = new AtomicInteger(0);
    
        public void increment() {
            count.incrementAndGet(); // Atomická operace
        }
    }
    

    Atomické proměnné poskytují atomické operace (například inkrementace, dekrementace), které jsou prováděny jako celek a nemohou být přerušeny jiným vláknem.

  4. Použití vlákně bezpečných kolekcí z balíčku java.util.concurrent: Například ConcurrentHashMap, CopyOnWriteArrayList. Tyto kolekce jsou navrženy tak, aby byly bezpečné pro použití ve vícevláknových prostředích.

  5. Vyhýbání se sdílenému měnitelnému stavu: Pokud je to možné, data přístupná více vláknům by měla být neměnná (immutable) nebo oddělena pro každé vlákno.

  6. Použití volatile: Klíčové slovo volatile zajišťuje viditelnost změn proměnné pro všechna vlákna, ale nezaručuje atomovost operací (s výjimkou čtení a zápisu primitivních typů, kromě long a double, a odkazů). Je užitečné ve spojení s jinými mechanismy nebo pro jednoduché, nezávislé operace na stavu.

    class VolatileFlag {
        volatile boolean flag = false; // Zajištěna viditelnost změn
    
        public void setFlag() {
            flag = true;
        }
    
        public boolean isFlag() {
            return flag;
        }
    }
    

Výběr vhodné metody závisí na konkrétní situaci a požadavcích na výkon a složitost kódu.