Sobes.tech
Middle

Co můžete říct o vícesměrných kolekcích v Java?

sobes.tech AI

Odpověď od AI

Kolekce v Java s více vlákny poskytují bezpečné způsoby práce s daty z více vláken současně, předcházejí závodním podmínkám a dalším problémům synchronizace.

Hlavní rozhraní a třídy zahrnují:

  • ConcurrentMap: Rozšiřuje Map a zajišťuje atomické operace.
    • ConcurrentHashMap: Vysoce výkonná implementace, která nezamyká celou mapu při modifikaci. Zajišťuje bezpečnost pro vlákna bez úplného zamykání.
  • CopyOnWriteArrayList a CopyOnWriteArraySet: Kolekce bezpečné pro vlákna, které při každé modifikaci vytvářejí kopii základního pole. Vhodné pro kolekce, které se často čtou a zřídka mění. Čtení probíhá bez blokování.
  • BlockingQueue: Rozhraní fronty podporující operace čekání, dokud fronta není prázdná nebo plná. Používá se k organizaci interakce mezi vlákny, například v vzoru producent-spotřebitel.
    • ArrayBlockingQueue: Implementace BlockingQueue založená na poli s pevnou kapacitou.
    • LinkedBlockingQueue: Implementace BlockingQueue založená na spojovaném seznamu s volitelnou kapacitou.
    • SynchronousQueue: Fronta s nulovou kapacitou. Každá vkládací operace čeká na odpovídající odebrání a naopak.
  • ConcurrentLinkedQueue: Bezpečná pro vlákna implementace Queue založená na spojovaném seznamu. Nepodporuje blokující operace.

Rozdíly od synchronizovaných kolekcí (Collections.synchronizedList, Collections.synchronizedMap atd.):

  • Synchronizované kolekce používají úplné zamykání na úrovni objektu, což může snižovat výkon při vysoké konkurenci.
  • Kolekce s více vlákny, jako je ConcurrentHashMap, používají jemnější zamykání nebo jiné mechanismy pro dosažení lepšího výkonu.
  • Iterátory synchronizovaných kolekcí mohou házet ConcurrentModificationException při modifikaci kolekce během iterace z jiného vlákna. Iterátory kolekcí s více vlákny jsou obvykle odolnější vůči takovým změnám.

Výběr konkrétní kolekce s více vlákny závisí na scénáři použití: frekvence čtení/zápisu, potřeba blokujících operací, požadavky na výkon atd.

Příklad použití ConcurrentHashMap:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentExample {

    private final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

    public void updateValue(String key, Integer value) {
        map.put(key, value); // Bezpečná operace pro vlákna
    }

    public Integer getValue(String key) {
        return map.get(key); // Bezpečná operace pro vlákna
    }

    public void incrementValue(String key) {
        // Atomická operace: pokud klíč neexistuje, vloží 1, jinak zvýší stávající hodnotu
        map.compute(key, (k, v) -> (v == null) ? 1 : v + 1);
    }
}

Příklad použití BlockingQueue:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;

public class ProducerConsumer {

    private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

    // Producent vlákno
    public void produce(Integer item) throws InterruptedException {
        queue.put(item); // Blokuje, pokud je fronta plná
        System.out.println("Produced: " + item);
    }

    // Spotřebitel vlákno
    public Integer consume() throws InterruptedException {
        Integer item = queue.take(); // Blokuje, pokud je fronta prázdná
        System.out.println("Consumed: " + item);
        return item;
    }
}