Sobes.tech
Middle

De ce apar curse de competiție între fire și cum se poate combate acest lucru?

sobes.tech AI

Răspuns de la AI

Condițiile de cursă (race conditions) apar atunci când mai multe fire de execuție accesează simultan date modifiable comune, iar rezultatul final depinde de ordinea în care sunt executate. Problema este că planificatorul de fire poate schimba firul în orice moment, iar o operație asupra datelor care pare atomică în cod poate fi întreruptă și executată în părți de către alte fire.

Lupta împotriva condițiilor de cursă se reduce la asigurarea unui acces corect la resursele comune. Metodele principale:

  • Sincronizare: Limitarea accesului simultan la secțiunile critice ale codului în care sunt utilizate datele comune. Mecanisme populare:

    • Cuvântul cheie synchronized: asigură blocare la nivel de obiect sau clasă.
    // Blocare la nivel de obiect
    synchronized (this) {
        // Secțiune critică
        sharedData++;
    }
    
    // Blocare la nivel de clasă
    synchronized (MyClass.class) {
        // Secțiune critică
        sharedStaticData++;
    }
    
    • Blocuri explicite (Lock interfață, ReentrantLock): Oferă mai multă flexibilitate, de exemplu, posibilitatea de a încerca să obțină blocarea sau de a o obține cu un timeout.
    Lock lock = new ReentrantLock();
    // ...
    lock.lock(); // Obține blocarea
    try {
        // Secțiune critică
        sharedData++;
    } finally {
        lock.unlock(); // Eliberează blocarea (obligatoriu în finally)
    }
    
  • Operații atomice: Utilizarea claselor din pachetul java.util.concurrent.atomic, care oferă operații atomice (de exemplu, incrementare, comparație și schimb) fără blocare explicită la nivel de fire.

    import java.util.concurrent.atomic.AtomicInteger;
    
    AtomicInteger atomicCounter = new AtomicInteger(0);
    // ...
    atomicCounter.incrementAndGet(); // Incrementare atomică
    
  • Colecții sigure pentru fire: Utilizarea colecțiilor din pachetul java.util.concurrent (de exemplu, ConcurrentHashMap, CopyOnWriteArrayList), proiectate pentru a funcționa în medii multi-thread.

  • Date imutabile: Dacă datele nu pot fi modificate după creare, accesul multiplă nu va provoca condiții de cursă.

  • Stocare Thread-Local: Fiecare fir are o copie proprie a variabilei, eliminând problema accesului comun.

Alegerea metodei depinde de situația concretă și de nivelul de sincronizare necesar. Sincronizarea excesivă poate duce la costuri semnificative și chiar deadlock-uri.