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

Concurrenthashmap i Java med eksempel

Denne guide hjælper dig med at forstå konceptet Concurrenthashmap i Java.

Derudover vil vi også se på Concurrenthashmaps interne implementering og forskellen mellem Concurrenthashmap, HashMap og HashTable.

Hvad du vil lære
  • Hvad er Concurrenthashmap i Java?
  • Hvorfor er Concurrenthashmap trådsikkert?
  • Hvornår har vi brug for Concurrenthashmap over HashMap eller HashTable?
  • Hvordan bruger du Concurrenthashmap ved at bruge et eksempel?
  • Hvad er Concurrenthashmap i Java?

Introduktion til ConcurrentHashMap i Java?

Hvad er det samtidige hash-kort?

Hvordan virker det?

Hvordan adskiller det sig fra HashTable?

Nå...hvis du skal deltage i et java-interview, så er der chancer for, at du vil blive stillet et par spørgsmål om java concurrent package.

Og ConcurrentHashMap er en vigtig klasse til stede i java.util.concurrent pakke.

Hvad er ConcurrentHashMap?

ConcurrentHashMap blev introduceret i Java 1.5, er en del af Java concurrent-pakken (java.util.concurrent).

Concurrent Hash Map blev introduceret som et alternativ til HashTable for at forbedre ydeevnen af ​​nøgleværdibaseret datastruktur i et flertrådsmiljø.

Selvom Concurrent hash-kortet ligner meget HashTable, er der en enorm forskel i deres interne implementering.

I modsætning til HashTable låser ConcurrentHashMap ikke kortet, når du henter data fra det.

Derudover låser ConcurrentHashMap heller ikke hele kortet, når du skriver data ind i det.

Internt samtidig hash-kort låser kun den del (bucket), hvor dataene skrives til.

ConcurrentHashMap klasse arver fra AbstractMap og den implementerer ConcurrentHashMap grænseflade.

public class ConcurrentHashMap<K,V>
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable

Nøglekarakteristika for ConcurrentHashMap

  • ConcurrentHashMap er den trådsikre version af HashMap det betyder ConcurrentHashMap kan være en foretrukken mulighed i et samtidig miljø.

Forskel mellem HashMap, ConcurrentHashMap og HashTable

HashMap gør det muligt for flere tråde at fungere samtidigt.

Derfor er der chancer for data-insisteren, når flere tråde udfører en operation på HashMap .

Derfor HashMap er ikke at foretrække (ikke trådsikker) i et multi-threaded miljø.

Kommer til Hash-bordet.

HashTable er en trådsikker nøgleværdibaseret datastruktur.

Det betyder ad gangen, at kun én tråd kan udføre nogle operationer på HashTable .

Hvorfor så HashTable er ikke god selv i multi-threaded scenarier?.

Lad os tage et kig på HashTable's kode.

public synchronized boolean isEmpty() {
        return count == 0;
    }
public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }
        ...
        ...

        addEntry(hash, key, value, index);
        return null;
    }

public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;
    }

Hvis du ser på ovenstående HashTable's kildekode, kan du bemærke, at alle put, get og isEmpty funktioner synkroniseres.

Det betyder, at hvis en tråd udfører en operation på HashTable , så kan en anden tråd ikke engang kalde isEmpty() for at kontrollere, om HashTable er tom eller ej.

Derfor kan vi konkludere, at præstationsmæssigt Hashtable er ikke en god mulighed.

Men hvordan er ConcurrentHashMap god i ydeevne?

ConcurrentHashMap i java ligner meget HashTable, men det blev introduceret for at overvinde disse præstationsproblemer.

At vide hvordan ConcurrentHashMap er god i ydeevne, lad os se på den interne implementering af ConcurrentHashMap .

public class ConcurrentHashMap<K,V> implements ConcurrentMap<K,V>

Grundlæggende implementerer ConcurrentHashMap ConcurrentMap, som giver en garanti for trådsikkerhed og atomicitet.

Det betyder, at ConcurrentHashMap også bruger de grundlæggende principper for HashMap, herunder Hashing, Bucket osv.

ConcurrentHashMap bruger internt bucket til at gemme data, og standardstørrelsen på buckets er 16.

I lighed med HashMap er hovedmetoderne i ConcurrentHashMap-klassen:

public V put(K key, V value)
public V get(Object key)
public V remove(Object key)
public boolean containsKey(Object key)

Hvordan ConcurrentHashMap repræsenterer et enkelt dataelement

ConcurrentHashMap internt brug en indre klasse Node for at repræsentere dataene.

 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        volatile V val;
        volatile Node<K,V> next;

Node-klassen er en simpel klasse, der repræsenterer nøglen og værdien af ​​dataene.

volatile Node<K,V> next;

Hvis du ser på ovenstående udsagn, vil du måske bemærke, at noden også indeholder referencen til det næste node-element.

Det betyder inde i én spand, ConcurrentHashMap gemmer alle elementer som en sammenkædet liste.

Nu hvor vi har en rimelig forståelse af, hvordan ConcurrentHashMap bruger Node klasse til repræsenterer et enkelt dataelement.

Hvordan ConcurrentHashMap gemmer et dataelement i bøtten

Som vi ved, er det som standard ConcurrentHashMap bruger segment array (standardstørrelsen af ​​arrayet er 16).

I modsætning til HashTable, ConcurrentHashMap giver bedre ydeevne ved at erstatte HashTable's Knyt bred lås til Segment brede låse.

I stedet for at låse selve det komplette kort, låser ConcurrentHashMaps put-operation kun et indeks af segment-arrayet.

Derfor som standard i ConcurrentHashMap , der kan være 16 segmentlåse, så tråd, der opererer i ét segmentindeks, vil ikke påvirke andre elementer, der findes i et andet segment.

For at konkludere kan vi sige, at 16 forskellige tråde kan udføre tilføjelses-/opdateringsoperationer samtidigt i det concurrentHashMap.

Sådan ændres segmentstørrelse

Segmentarraystørrelsen bestemmer, hvor mange tråde der kan udføre put-operation samtidigt på ConcurrentHashMap .

ConcurrentHashMap<String, String> concurrentMap = new ConcurrentHashMap<>(20, 0.75f, 5);

I ovenstående eksempel er 20 initialCapacity , 0.75f ​​er loadFactor , og 5 er concurrencyLevel .

initialCapacity angiver, hvor mange elementer samtidig hash-kort kan have for at rumme så mange (20) elementer.

loadFactor er 0,75f, hvilket betyder, at når kortets størrelse overstiger 15 (20*.75=15), så er det tid til at øge kortets størrelse.

concurrencyLevel bestemmer størrelsen af ​​segmentarrayet. I vores eksempel har vi specificeret concurrencyLevel 10, hvilket betyder, at segmentstørrelsen på et givet tidspunkt vil være 10 eller mere end 10.

For at beregne segmentstørrelsen bruger vi formlen 2 X >= concurrencyLevel .

Størrelse på segmentmatrix =2 X >=10 =16.

Derfor ville segmentstørrelsen være 16.

Sådan udføres operationen i ConcurrentHashMap

En af de bedste funktioner i ConcurrentHashMap er et hvilket som helst antal tråde, kan udføre læseoperationer.

ConcurrentHashMap låser ikke et segment, mens du udfører en hentning.

ConcurrentHashMap (CHM) eksempel

Før du skriver et eksempel, er det godt at vide, at CHM ikke tillader null-nøgle eller værdi.

Exception in thread "main" java.lang.NullPointerException
	at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
	at java.base/java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006)
	at com.codedelay.corejava.ConcurrentHashMapDemo.main(ConcurrentHashMapDemo.java:19)
package com.codedelay.corejava;

import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ConcurrentHashMapDemo {

	public static void main(String[] args) {
		Student s1 = new Student(1001, "Mark");
		Student s2 = new Student(1001, "Adam");
		Student s3 = new Student(1001, "Sara");
		Student s4 = new Student(1001, "Mathew");
		Student s5 = new Student(1001, "John");
		
		//Put operation
		ConcurrentHashMap<Integer, Student> concurrentMap = new ConcurrentHashMap<>(20, 0.75f, 5);
		concurrentMap.put(1, s1);
		concurrentMap.put(2, s2);
		concurrentMap.put(3, s3);
		concurrentMap.put(4, s4);
		concurrentMap.put(5, s5);
		
		//retrive value from concurrentHashMap
		for (Map.Entry<Integer, Student> e : concurrentMap.entrySet()) {
            System.out.println(e.getKey() + " = " + e.getValue());
        }
	}
}
package com.codedelay.corejava;

public class Student {
	private int studentId;
	private String studentName;
	public Student(int studentId, String studentName) {
		this.studentId = studentId;
		this.studentName = studentName;
	}
	public int getStudentId() {
		return studentId;
	}
	public String getStudentName() {
		return studentName;
	}
	@Override
	public String toString() {
		return "Student [studentId=" + studentId + ", studentName=" + studentName + "]";
	}
}

Konklusion

I denne øvelse diskuterede vi ConcurrentHashMap i java og dets interne implementering.


Java tag