En introduktion til synkroniserede Java-samlinger

1. Oversigt

Samlingsrammen er en nøglekomponent i Java. Det giver et omfattende antal grænseflader og implementeringer, som giver os mulighed for at oprette og manipulere forskellige typer samlinger på en ligetil måde.

Selvom brug af almindelige usynkroniserede samlinger generelt er simpelt, kan det også blive en afskrækkende og fejlbehæftet proces, når du arbejder i miljøer med flere tråde (altså samtidig programmering).

Derfor giver Java-platformen stærk støtte til dette scenarie gennem forskellige synkroniseringer indpakninger implementeret inden for Samlinger klasse.

Disse indpakninger gør det nemt at oprette synkroniserede visninger af de leverede samlinger ved hjælp af flere statiske fabriksmetoder.

I denne vejledning vi dykker dybt ned i disse statisk synkroniseringsindpakning. Vi fremhæver også forskellen mellem synkroniserede samlinger og samtidige samlinger.

2. Den synchronizedCollection () Metode

Den første synkroniseringsindpakning, som vi dækker i denne runde, er synchronizedCollection () metode. Som navnet antyder, det returnerer en trådsikker samling bakket op af det angivne Kollektion.

For at forstå mere klart, hvordan man bruger denne metode, lad os nu oprette en grundlæggende enhedstest:

Collection syncCollection = Collections.synchronizedCollection (ny ArrayList ()); Kørbar listeOperationer = () -> {syncCollection.addAll (Arrays.asList (1, 2, 3, 4, 5, 6)); }; Tråd tråd1 = ny tråd (listOperations); Tråd tråd2 = ny tråd (listOperations); thread1.start (); thread2.start (); thread1.join (); thread2.join (); assertThat (syncCollection.size ()). er EqualTo (12); } 

Som vist ovenfor er det meget simpelt at oprette en synkroniseret visning af den leverede samling med denne metode.

For at demonstrere, at metoden rent faktisk returnerer en trådsikker samling, opretter vi først et par tråde.

Derefter injicerer vi derefter en Kan køres eksempel i deres konstruktører i form af et lambda-udtryk. Lad os huske det Kan køres er en funktionel grænseflade, så vi kan erstatte den med et lambda-udtryk.

Endelig kontrollerer vi bare, at hver tråd effektivt tilføjer seks elementer til den synkroniserede samling, så dens endelige størrelse er tolv.

3. Den synchronizedList () Metode

Ligeledes ligner synchronizedCollection () metode, kan vi bruge synchronizedList () indpakning for at oprette en synkroniseret Liste.

Som vi kunne forvente, metoden returnerer en trådsikker visning af det specificerede Liste:

Liste syncList = Collections.synchronizedList (ny ArrayList ());

Ikke overraskende er brugen af synkroniseret liste () metoden ser næsten identisk ud med dens modstykke på højere niveau, synchronizedCollection ().

Derfor, som vi lige gjorde i den forrige enhedstest, når vi først har oprettet en synkroniseret Liste, vi kan gyde flere tråde. Efter at have gjort det, bruger vi dem til at få adgang til / manipulere målet Liste på en trådsikker måde.

Derudover, hvis vi ønsker at gentage en synkroniseret samling og forhindre uventede resultater, skal vi eksplicit give vores egen trådsikker implementering af sløjfen. Derfor kunne vi opnå det ved hjælp af en synkroniseret blok:

Liste syncCollection = Collections.synchronizedList (Arrays.asList ("a", "b", "c")); Liste med store bogstaverCollection = ny ArrayList (); Kørbar listeOperationer = () -> {synkroniseret (syncCollection) {syncCollection.forEach ((e) -> {uppercasedCollection.add (e.toUpperCase ());}); }}; 

I alle tilfælde, hvor vi har brug for at gentage over en synkroniseret samling, skal vi implementere dette udtryk. Dette skyldes, at iteration på en synkroniseret samling udføres gennem flere opkald til samlingen. Derfor skal de udføres som en enkelt atomoperation.

Brugen af synkroniseret blok sikrer operationens atomicitet.

4. Den synchronizedMap () Metode

Det Samlinger klasse implementerer en anden pæn synkroniseringsindpakning, kaldet synchronizedMap (). Vi kunne bruge det til let at oprette en synkroniseret Kort.

Metoden returnerer en trådsikker visning af det leverede Kort implementering:

Kort syncMap = Collections.synchronizedMap (nyt HashMap ()); 

5. Den synchronizedSortedMap () Metode

Der er også en modstykke implementering af synchronizedMap () metode. Det kaldes synchronizedSortedMap (), som vi kan bruge til at oprette en synkroniseret SortedMap eksempel:

Kort syncSortedMap = Collections.synchronizedSortedMap (nyt TreeMap ()); 

6. Den synchronizedSet () Metode

Dernæst fortsætter vi i denne anmeldelse og har synchronizedSet () metode. Som navnet antyder, tillader det os at oprette synkroniseret Sæt med minimalt besvær.

Indpakningen returnerer en trådsikker samling bakket op af det angivne Sæt:

Indstil syncSet = Collections.synchronizedSet (nyt HashSet ()); 

7. Den synchronizedSortedSet () Metode

Endelig er den sidste synkroniseringsindpakning, som vi viser her synchronizedSortedSet ().

Svarende til andre wrapperimplementeringer, som vi hidtil har gennemgået, metoden returnerer en trådsikker version af det givne SortedSet:

SortedSet syncSortedSet = Collections.synchronizedSortedSet (nyt TreeSet ()); 

8. Synkroniseret vs samtidige samlinger

Indtil dette punkt kiggede vi nærmere på samlingens rammes synkroniseringsindpakninger.

Lad os nu fokusere på forskellene mellem synkroniserede samlinger og samtidige samlinger, såsom ConcurrentHashMap og BlockingQueue implementeringer.

8.1. Synkroniserede samlinger

Synkroniserede samlinger opnår trådsikkerhed gennem indre låsning, og hele samlingen er låst. Intrinsic locking implementeres via synkroniserede blokke inden for den indpakkede samlings metoder.

Som vi kunne forvente, sikrer synkroniserede samlinger datakonsistens / integritet i miljøer med flere tråde. Imidlertid kan de komme med en straf i ydeevne, da kun en enkelt tråd kan få adgang til samlingen ad gangen (aka synkroniseret adgang).

For en detaljeret vejledning om, hvordan du bruger synkroniseret metoder og blokke, se vores artikel om emnet.

8.2. Samtidige samlinger

Samtidige samlinger (f.eks. ConcurrentHashMap), opnå trådsikkerhed ved at opdele deres data i segmenter. I en ConcurrentHashMapfor eksempel kan forskellige tråde få låse på hvert segment, så flere tråde kan få adgang til Kort på samme tid (alias samtidig adgang).

Samtidige samlinger er meget mere performant end synkroniserede samlingerpå grund af de iboende fordele ved samtidig trådadgang.

Så valget af hvilken type trådsikker samling, der skal bruges, afhænger af kravene i hver brugssag, og det skal evalueres i overensstemmelse hermed.

9. Konklusion

I denne artikel tog vi et dybtgående kig på det sæt synkroniseringsindpakninger, der er implementeret i Samlinger klasse.

Derudover fremhævede vi forskellene mellem synkroniserede og samtidige samlinger og så også på de tilgange, de implementerer for at opnå trådsikkerhed.

Som sædvanligt er alle kodeeksempler vist i denne artikel tilgængelige på GitHub.