Middle
Ce poți spune despre colecțiile multi-thread în Java?
sobes.tech AI
Răspuns de la AI
Colecțiile concurente din Java oferă modalități sigure de a lucra cu date din mai multe fire de execuție simultan, prevenind condițiile de cursă și alte probleme de sincronizare.
Interfețele și clasele principale includ:
ConcurrentMap: ExtindeMapși asigură operații atomice.ConcurrentHashMap: Implementare de înaltă performanță care nu blochează întreaga hartă în timpul modificărilor. Asigură siguranța firelor fără blocare completă.
CopyOnWriteArrayListșiCopyOnWriteArraySet: Colecții sigure pentru fire, care creează o copie a array-ului de bază la fiecare modificare. Sunt potrivite pentru colecții citite frecvent și modificate rar. Citirea se face fără blocare.BlockingQueue: Interfață de coadă care suportă operații de așteptare până când coada devine goală sau plină. Este utilizată pentru organizarea interacțiunii între fire, de exemplu în modelul producer-consumer.ArrayBlockingQueue: Implementare aBlockingQueuebazată pe array cu capacitate fixă.LinkedBlockingQueue: Implementare aBlockingQueuebazată pe listă legată cu capacitate opțională.SynchronousQueue: Coadă cu capacitate zero. Fiecare operație de inserție așteaptă o operație de extragere corespunzătoare și invers.
ConcurrentLinkedQueue: Implementare sigură pentru fire aQueuebazată pe listă legată. Nu suportă operații de blocare.
Diferențe față de colecțiile sincronizate (Collections.synchronizedList, Collections.synchronizedMap etc.):
- Colecțiile sincronizate utilizează blocare completă la nivel de obiect, ceea ce poate reduce performanța în cazul concurenței ridicate.
- Colecțiile concurente, precum
ConcurrentHashMap, utilizează blocări mai granulare sau alte mecanisme pentru a obține performanțe mai bune. - Iteratorii colecțiilor sincronizate pot arunca
ConcurrentModificationExceptiondacă colecția este modificată în timpul iterării de către alt fir. Iteratorii colecțiilor concurente sunt de obicei mai rezistenți la astfel de modificări.
Alegerea unei colecții concurente specifice depinde de scenariul de utilizare: frecvența citirii/scrierii, necesitatea operațiilor de blocare, cerințele de performanță etc.
Exemplu de utilizare a 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); // Operație sigură pentru fire
}
public Integer getValue(String key) {
return map.get(key); // Operație sigură pentru fire
}
public void incrementValue(String key) {
// Operație atomică: dacă cheia nu există, inserează 1, altfel crește valoarea existentă
map.compute(key, (k, v) -> (v == null) ? 1 : v + 1);
}
}
Exemplu de utilizare a BlockingQueue:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
public class ProducerConsumer {
private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// Producător
public void produce(Integer item) throws InterruptedException {
queue.put(item); // Se blochează dacă coada este plină
System.out.println("Produced: " + item);
}
// Consumator
public Integer consume() throws InterruptedException {
Integer item = queue.take(); // Se blochează dacă coada este goală
System.out.println("Consumed: " + item);
return item;
}
}