Ce face Collections.synchronizedList
Un ArrayList obișnuit nu suportă să fie modificat în același timp de mai multe fire de execuție (threads): pot dispărea elemente sau pot apărea excepții. Collections.synchronizedList(lista) returnează o vedere în care fiecare apel (add, get, size…) este protejat de un lacăt: un singur fir lucrează pe listă la un moment dat.
Parcurgerea nu este protejată automat. Când parcurgi lista (for-each, iterator, stream), pune bucla într-un bloc synchronized (lista) { ... }, altfel alt fir o poate modifica în timpul parcurgerii.
Pentru cod nou cu multe fire, clasele din java.util.concurrent sunt de obicei mai potrivite: CopyOnWriteArrayList (multe citiri, puține scrieri), ConcurrentHashMap, ConcurrentLinkedQueue.
Parametri
| Parametru | Descriere |
|---|---|
list |
Lista care trebuie protejată. După înveliș, folosește doar vederea. |
Ce returnează
O vedere sincronizată a listei.
Exemple
Exemplul 1: Patru fire adaugă în aceeași listă
Fiecare fir adaugă 1000 de numere. Cu lista sincronizată, la final sunt exact 4000. join() așteaptă terminarea firelor.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) throws InterruptedException {
List<Integer> comenzi = Collections.synchronizedList(new ArrayList<>());
List<Thread> fire = new ArrayList<>();
for (int f = 0; f < 4; f++) {
Thread t = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
comenzi.add(i);
}
});
fire.add(t);
t.start();
}
for (Thread t : fire) {
t.join();
}
System.out.println("Comenzi înregistrate: " + comenzi.size());
}
}
Rezultat
Comenzi înregistrate: 4000
Exemplul 2: Parcurgerea se face într-un bloc synchronized
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> jurnal = Collections.synchronizedList(new ArrayList<>());
jurnal.add("08:00 pornit");
jurnal.add("08:05 conectat la baza de date");
jurnal.add("08:06 gata");
synchronized (jurnal) {
for (String linie : jurnal) {
System.out.println(linie);
}
}
}
}
Rezultat
08:00 pornit
08:05 conectat la baza de date
08:06 gata
Greșeli frecvente
- Parcurgi lista sincronizată fără
synchronized (lista)în timp ce alte fire scriu. Poate apăreaConcurrentModificationException. - Păstrezi și folosești în continuare lista originală, neînvelită. Accesul prin ea nu este protejat.
- Crezi că două apeluri la rând sunt atomice:
if (!lista.contains(x)) lista.add(x);. Alt fir poate interveni între ele; pune ambele într-un blocsynchronized (lista).
Comenzi înrudite
Collections.unmodifiableList: Returnează o vedere doar-pentru-citire a unei liste: cine o primește nu o poate modifica, dar schimbările originalului se văd.ArrayList: Lista implementată cu un array intern care crește automat; acces foarte rapid după index. Cea mai folosită listă din Java.Thread: Un fir de execuție: cod care rulează în paralel cu restul programului. start() îl pornește, join() așteaptă să se termine.HashMap: Dicționarul cel mai rapid: put, get și remove în timp aproape constant, dar fără ordine garantată a cheilor.