Java >> Java tutorial >  >> Tag >> synchronized

Har du brug for manuelt at synkronisere den synkroniserede liste under iteration, når det kunne undgås?

Jeg tror, ​​at iteratormetoden også kunne have håndteret synkronisering på samme måde som metoden ovenfor

Nej, det kunne den absolut ikke.

Iteratoren har ingen kontrol over, hvad din kode gør mellem opkald til de individuelle metoder på den. Det er pointen. Din iterationskode kalder hasNext() og next() gentagne gange og synkronisering under disse opkald er mulige, men irrelevante - det vigtige er, at ingen anden kode forsøger at ændre listen på tværs af hele tiden, du gentager .

Så forestil dig en tidslinje af:

t = 0: call iterator()
t = 1: call hasNext()
t = 2: call next()
// Do lots of work with the returned item
t = 10: call hasNext()

Iteratoren kan ikke synkronisere mellem slutningen af ​​opkaldet til next() ved t=2 og opkaldet til hasNext() ved t=10. Så hvis en anden tråd forsøger at (f.eks.) tilføje et element til listen ved t=7, hvordan skal iteratoren forhindre det i at gøre det?

Dette er det overordnede problem med synkroniserede samlinger:hver individ operationen er synkroniseret, hvorimod du typisk ønsker, at en hel chunky operation skal synkroniseres.


Hvis du ikke synkroniserer hele iterationen, kan en anden tråd ændre samlingen, mens du itererer, hvilket fører til en ConccurentModificationException.

Den returnerede iterator er heller ikke trådsikker.
De kunne løse det ved at pakke iteratoren ind i en SynchronizedIterator der låser hver metode i iteratoren, men det ville heller ikke hjælpe – en anden tråd kunne stadig ændre samlingen mellem to iterationer og bryde alt.

Dette er en af ​​grundene til, at Collections.synchronized*() metoder er fuldstændig ubrugelige.
For mere information om korrekt brug af trådsikker indsamling, se min blog.


Hvis du vil undgå manuel synkronisering, skal du bruge en samling som java.util.concurrent.CopyOnWriteArrayList . Hver gang et objekt føjes til listen, kopieres den underliggende datastruktur for at undgå en samtidig modifikationsundtagelse.

Grunden til, at du har brug for manuel serialisering på iteratoren i dit eksempel, er, at iteratoren bruger den samme interne datastruktur som listen, men de er uafhængige objekter, og både iterator og liste kan tilgås af forskellige tråde på ethvert vilkårligt tidspunkt.

En anden metode ville være at lave en lokal kopi af listen og gentage kopien.


Java tag