Java >> Java tutorial >  >> Tag >> HashMap

Java Concurrent HashSet svarende til ConcurrentHashMap

1. Oversigt

I denne vejledning vil vi se, hvilke muligheder der er for at skabe trådsikkert HashSet instanser og hvad der svarer til ConcurrentHashMap til HashSet . Desuden vil vi se på fordele og ulemper ved hver tilgang.

2. Trådsikkert HashSet Brug af ConcurrentHashMap Fabriksmetode

Først vil vi se på ConcurrentHashMap klasse, der afslørede det statiske newKeySet() metode. Grundlæggende returnerer denne metode en instans, der respekterer java.util.Set grænseflade og tillader brug af standardmetoder som add(), contains(), osv.

Dette kan oprettes som:

Set<Integer> threadSafeUniqueNumbers = ConcurrentHashMap.newKeySet();
threadSafeUniqueNumbers.add(23);
threadSafeUniqueNumbers.add(45);

Yderligere ydeevnen af ​​det returnerede Set ligner Har hSet , da begge er implementeret ved hjælp af en hash-baseret algoritme. Desuden er den ekstra overhead, der pålægges af synkroniseringslogikken, også minimal, fordi implementeringen bruger et ConcurrentHashMap .

Endelig er ulempen, at metoden eksisterer kun startende med Java 8 .

3. Trådsikkert HashSet Brug af ConcurrentHashMap Forekomstmetoder

Indtil videre har vi set på den statiske metode ConcurrentHashMap. Dernæst vil vi tage fat på de instansmetoder, der er tilgængelige for ConcurrentHashMap for at oprette trådsikkert Set tilfælde. Der er to tilgængelige metoder, newKeySet() og newKeySet(defaultValue) som afviger lidt fra hinanden.

Begge metoder opretter et sæt , som er forbundet med det originale kort . For at sige det anderledes, hver gang vi tilføjer en ny post til det oprindelige ConcurrentHashMap, sættet vil modtage den værdi. Lad os yderligere se på forskellene mellem disse to metoder.

3.1. newKeySet() Metode

Som nævnt ovenfor, newKeySet() afslører et Set indeholdende alle nøgler til det oprindelige kort. Den vigtigste forskel mellem denne metode og newKeySet(defaultValue) er, at den nuværende ikke understøtter tilføjelse af nye elementer til Sættet . Så hvis vi forsøger at kalde metoder som add() eller addAll(), vi får en UnsupportedOperationException .

Selvom operationer som remove(object) eller clear() fungerer som forventet, skal vi være opmærksomme på, at enhver ændring på sættet vil blive afspejlet i det originale kort:

ConcurrentHashMap<Integer,String> numbersMap = new ConcurrentHashMap<>();
Set<Integer> numbersSet = numbersMap.keySet();

numbersMap.put(1, "One");
numbersMap.put(2, "Two");
numbersMap.put(3, "Three");

System.out.println("Map before remove: "+ numbersMap);
System.out.println("Set before remove: "+ numbersSet);

numbersSet.remove(2);

System.out.println("Set after remove: "+ numbersSet);
System.out.println("Map after remove: "+ numbersMap);

Dernæst er outputtet af koden ovenfor:

Map before remove: {1=One, 2=Two, 3=Three}
Set before remove: [1, 2, 3]

Set after remove: [1, 3]
Map after remove: {1=One, 3=Three}

3.2. newKeySet(defaultValue) Metode

Lad os se på en anden måde at oprette et sæt på ud af tasterne på kortet. Sammenlignet med den ovenfor nævnte, newKeySet(defaultValue) returnerer et Set instans, der understøtter tilføjelse af nye elementer ved at kalde add() eller addAll() på settet.

Når man ser på standardværdien, der sendes som en parameter, bruges denne som værdien for hver ny post i kortet tilføjet tanke add() eller addAll() metoder. Følgende eksempel viser, hvordan dette fungerer:

ConcurrentHashMap<Integer,String> numbersMap = new ConcurrentHashMap<>();
Set<Integer> numbersSet = numbersMap.keySet("SET-ENTRY");

numbersMap.put(1, "One");
numbersMap.put(2, "Two");
numbersMap.put(3, "Three");

System.out.println("Map before add: "+ numbersMap);
System.out.println("Set before add: "+ numbersSet);

numbersSet.addAll(asList(4,5));

System.out.println("Map after add: "+ numbersMap);
System.out.println("Set after add: "+ numbersSet);

Nedenfor er outputtet af koden ovenfor:

Map before add: {1=One, 2=Two, 3=Three}
Set before add: [1, 2, 3]
Map after add: {1=One, 2=Two, 3=Three, 4=SET-ENTRY, 5=SET-ENTRY}
Set after add: [1, 2, 3, 4, 5]

4. Trådsikkert HashSet Brug af Samlinger Hjælpeklasse

Lad os bruge synchronizedSet() metode tilgængelig i java.util.Collections for at skabe et trådsikkert HashSet eksempel:

Set<Integer> syncNumbers = Collections.synchronizedSet(new HashSet<>());
syncNumbers.add(1);

Før vi bruger denne tilgang, skal vi være opmærksomme på, at den er mindre effektiv end dem, der er diskuteret ovenfor . Grundlæggende synchronizedSet() ombryder bare sættet instans til en synkroniseret dekorator sammenlignet med ConcurrentHashMap der implementerer en samtidighedsmekanisme på lavt niveau.

5. Trådsikkert sæt Brug af CopyOnWriteArraySet

Den sidste tilgang til at skabe trådsikkert Set implementeringer er CopyOnWriteArraySet . Oprettelse af en forekomst af dette sæt er simpelt:

Set<Integer> copyOnArraySet = new CopyOnWriteArraySet<>();
copyOnArraySet.add(1);

Selvom det ser tiltalende ud at bruge denne klasse, er vi nødt til at overveje nogle alvorlige ydeevne ulemper. Bag scenen, CopyOnWriteArraySet bruger en Array, ikke et HashMap, at gemme dataene. Dette betyder, at operationer som contains() eller remove() har O(n) kompleksitet, mens du bruger sæt understøttet af ConcurrentHashMap, kompleksiteten er O(1).

Det anbefales at bruge denne implementering, når Set størrelse forbliver generelt lille, og skrivebeskyttede operationer har et flertal.

6. Konklusioner

I denne artikel har vi set forskellige muligheder for at skabe trådsikkert Set tilfælde og understregede forskellene mellem dem. For det første har vi set ConcurrentHashMap.newKeySet()  statisk metode. Dette bør være det første valg, når et trådsikkert HashSet er nødvendig . Bagefter undersøgte vi, hvad der er forskellene mellem ConcurrentHashMap statisk metode og newKeySet(), newKeySet(defaultValue) for ConcurrentHashMap  forekomster.

Til sidst diskuterede vi også Samlinger. synchronizedSet() og CopyOnWriteArraySet   og der ydeevne ulemper.

Som sædvanlig er den komplette kildekode tilgængelig på GitHub.


Java tag