DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • ConcurrentHashMap: Call Only One Method Per Key
  • Java Concurrency: Understanding the ‘Volatile’ Keyword
  • DataWeave Interview Question: Concatenate Elements of an Array
  • Floyd's Cycle Algorithm for Fraud Detection in Java Systems

Trending

  • Immutable Secrets Management: A Zero-Trust Approach to Sensitive Data in Containers
  • AI's Dilemma: When to Retrain and When to Unlearn?
  • DGS GraphQL and Spring Boot
  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  1. DZone
  2. Coding
  3. Java
  4. How ConcurrentHashMap Works Internally in Java

How ConcurrentHashMap Works Internally in Java

Understanding how ConcurrentHashMap works with a list of concrete examples.

By 
Arun Pandey user avatar
Arun Pandey
DZone Core CORE ·
Sep. 06, 16 · Tutorial
Likes (66)
Comment
Save
Tweet
Share
470.5K Views

Join the DZone community and get the full member experience.

Join For Free

Before talking in detail let us review a few concepts below:

ConcurrentHashMap: It allows concurrent access to the map. Part of the map called Segment (internal data structure) is only getting locked while adding or updating the map. So ConcurrentHashMap allows concurrent threads to read the value without locking at all. This data structure was introduced to improve performance.

Concurrency-Level: Defines the number which is an estimated number of concurrently updating threads. The implementation performs internal sizing to try to accommodate this     many threads.    

Load-Factor: It's a threshold, used to control resizing.

Initial Capacity: The implementation performs internal sizing to accommodate these many elements.

A ConcurrentHashMap is divided into number of segments, and the example which I am explaining here used default as 32 on initialization.

A ConcurrentHashMap has internal final class called Segment so we can say that ConcurrentHashMap is internally divided in segments of size 32, so at max 32 threads can work at a time. It means each thread can work on a each segment during high concurrency and atmost 32 threads can operate at max which simply maintains 32 locks to guard each bucket of the ConcurrentHashMap.

The definition of Segment is as below:

/** Inner Segment class plays a significant role **/
protected static final class Segment {
  protected int count;

  protected synchronized int getCount() {
    return this.count;
  }

  protected synchronized void synch() {}
}

/** Segment Array declaration **/
public final Segment[] segments = new Segment[32];

As we all know that Map is a kind of data structure which stores data in key-value pair which is array of inner class Entry, see as below:

 static class Entry implements Map.Entry {      
   protected final Object key;
   protected volatile Object value;
   protected final int hash;
   protected final Entry next;

   Entry(int hash, Object key, Object value, Entry next) {

     this.value = value;
     this.hash = hash;
     this.key = key;
     this.next = next;
   }

   // Code goes here like getter/setter
 }

And ConcurrentHashMap class has an array defined as below of type Entry class: 

 protected transient Entry[] table; 

This Entry array is getting initialized when we are creating an instance of ConcurrentHashMap, even using a default constructor called internally as below:

public ConcurrentHashMap(int initialCapacity, float loadFactor) {

  //Some code
  int cap = getCapacity();
  this.table = newTable(cap); // here this.table is Entry[] table
}

protected Entry[] newTable(int capacity) {
  this.threshold = ((int)(capacity * this.loadFactor / 32.0F) + 1);
  return new Entry[capacity];
}

Here, threshold is getting initialized for re-sizing purpose.

Inserting (Put) Element in ConcurrentHashMap:

Most important thing to understand the put method of ConcurrentHashMap, that how ConcurrentHashMap works when we are adding the element. As we know put method takes two arguments both of type Object as below:

put(Object key, Object value)    

So it wil 1st calculate the hash of key as below:

int hashVal = hash(key);

static int hash(Object x) {
  int h = x.hashCode();
  return (h << 7) - h + (h >>> 9) + (h >>> 17);
}

After getting the hashVal we can decide the Segment as below:

Segment seg = segments[(hash & 0x1F)];     // segments is an array defined above 
   
Since it's all about concurrency, we need synchronized block on the above Segment as below:

synchronized (seg) {
  // code to add

  int index = hash & table.length - 1; // hash we have calculated for key and table is Entry[] table
  Entry first = table[index];
  for (Entry e = first; e != null; e = e.next) {
    if ((e.hash == hash) && (eq(key, e.key))) { // if key already exist means updating the value
      Object oldValue = e.value;
      e.value = value;
      return oldValue;
    }
  }

  Entry newEntry = new Entry(hash, key, value, first); // new entry, i.e. this key not exist in map
  table[index] = newEntry; // Putting the Entry object at calculated Index 
}


Size of ConcurrentHashMap

Now when we are asking for size() of the ConcurrentHashMap the size comes out as below:

for (int i = 0; i < this.segments.length; i++) {
  c += this.segments[i].getCount();         //here c is an integer initialized with zero
}   


Getting (get) Element From ConcurrentHashMap

When we are getting an element from ConcurrentHashMap we are simply passing key and hash of key is getting calculated. The defintion goes something like as below:

public Object get(Object key){
  //some  code here

  int index = hash & table.length - 1;  //hash we have calculated for key and calculating index with help of hash
  Entry first = table[index];          //table is Entry[] table
  for (Entry e = first; e != null; e = e.next) {
    if ((e.hash == hash) && (eq(key, e.key))) {
      Object value = e.value;
      if (value == null) {
        break;
      }
      return value;
    }
  }
  //some  code here
}

Note: No need to put any lock when getting the element from ConcurrentHashMap.

Removing Element From ConcurrentHashMap

Now question is how remove works with ConcurrentHashMap, so let us understand it. Remove basically takes one argument 'Key' as an argument or takes two argument 'Key' and 'Value' as below:

Object remove(Object key);

boolean remove(Object key, Object value);

Now let us understand how this works internally. The method remove (Object key) internally calls remove (Object key, Object value) where it passed 'null' as a value. Since we are going to remove an element from a Segment, we need a lock on the that Segment.

Object remove(Object key, Object value) {

  Segment seg = segments[(hash & 0x1F)]; //hash we have calculated for key

  synchronized (seg) {
    Entry[] tab = this.table; //table is Entry[] table    
    int index = hash & tab.length - 1; //calculating index with help of hash
    Entry first = tab[index]; //Getting the Entry Object

    Entry e = first;
    while(true) {
      if ((e.hash == hash) && (eq(key, e.key))) {
        break;
      }
      e = e.next;
    }
    Object oldValue = e.value;
    Entry head = e.next;
    for (Entry p = first; p != e; p = p.next) {
      head = new Entry(p.hash, p.key, p.value, head);
    }
    table[index] = head;
    seg.count -= 1;
  }
  return oldValue;
}

Hope this will give you a clear understanding of the internal functionality of ConcurrentHashMap.

Data structure Element Java (programming language) Threading

Opinions expressed by DZone contributors are their own.

Related

  • ConcurrentHashMap: Call Only One Method Per Key
  • Java Concurrency: Understanding the ‘Volatile’ Keyword
  • DataWeave Interview Question: Concatenate Elements of an Array
  • Floyd's Cycle Algorithm for Fraud Detection in Java Systems

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!