Sobes.tech
Middle

Koje načine borbe sa trkaćim uslovima niti, osim korišćenja ključne reči volatile, poznajete?

sobes.tech АИ

Одговор од АИ

Postoji nekoliko osnovnih pristupa za sinhronizaciju niti i sprečavanje trkaćih uslova u Androidu, pored volatile.

  1. Korišćenje synchronized: Blokira pristup kodu ili metodi za druge niti do završetka trenutne niti.

    // Sinhronizovana metoda
    synchronized void incrementCounter() {
        counter++;
    }
    
    // Sinhronizovani blok
    void updateData() {
        synchronized (this) { // ili drugi monitor objekat
            // kod koji zahteva sinhronizaciju
        }
    }
    
  2. Korišćenje klasa iz paketa java.util.concurrent.locks: Nude fleksibilnije mehanizme zaključavanja od synchronized.

    import java.util.concurrent.locks.ReentrantLock;
    
    private final ReentrantLock lock = new ReentrantLock();
    
    void performLockedOperation() {
        lock.lock(); // Dobijanje zaključavanja
        try {
            // kod zaštićen zaključavanjem
        } finally {
            lock.unlock(); // oslobađanje zaključavanja (važno u finally)
        }
    }
    
  3. Korišćenje klasa iz paketa java.util.concurrent.atomic: Nude atomarne operacije koje se izvršavaju kao celina bez prekida od strane drugih niti. Pogodno za jednostavne operacije nad primitivnim tipovima i referencama.

    import java.util.concurrent.atomic.AtomicInteger;
    
    private final AtomicInteger atomicCounter = new AtomicInteger(0);
    
    void incrementAtomicCounter() {
        atomicCounter.incrementAndGet(); // Atomno povećanje
    }
    
  4. Korišćenje bezbednih kolekcija: Kolekcije iz paketa java.util.concurrent (npr. ConcurrentHashMap, CopyOnWriteArrayList) su dizajnirane za bezbednu upotrebu u višestrukim nitima bez eksplicitne sinhronizacije od strane programera.

    import java.util.concurrent.ConcurrentHashMap;
    import java.util.Map;
    
    private final Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
    
    void updateMap(String key, Integer value) {
        concurrentMap.put(key, value); // bezbedna operacija upisa
    }
    
  5. Korišćenje ThreadLocal: Omogućava kreiranje promenljive koja će imati zasebnu kopiju za svaku nit. Na taj način, svaka nit radi sa sopstvenim podacima, izbegavajući trke.

    private final ThreadLocal<Integer> threadLocalValue = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0; // početna vrednost za svaku nit
        }
    };
    
    void processData() {
        int value = threadLocalValue.get();
        value++;
        threadLocalValue.set(value); // postavljanje vrednosti za trenutnu nit
    }
    

Izbor metode zavisi od specifikacije zadatka, potrebe za zaključavanjem, tipa podataka i zahtevanog performansa.