Learnitweb

ConcurrentHashMap in Java

1. Introduction

Even though Hashtable is thread safe, it is not very efficient. You can also create a synchronized collection using Collections.synchronizedMap, but it is also not efficient. If we want thread-safety with high throughput under high concurrency, you can use ConcurrentHashMap.

Following are some important points about ConcurrentHashMap:

  • ConcurrentHashMap is defined in java.util.concurrent package. This class is a member of the Java Collections Framework. This class implements Serializable, ConcurrentMap and Map interfaces.
  • All operations of this class are thread-safe.
  • This class is similar to HashTable.
  • This class does not provide the support to lock the entire table during access.
  • Retrieval operations of this class does not result in locking and are non-blocking.
  • Retrieval operations are non-blocking and can be used simultaneously with updated operations like put and remove. Retrieval operations return the most recent updated value at that instant.
  • An update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key.
  • Iterators, Spliterators and Enumerations return elements reflecting most recent state at the time of its creation. They do not throw ConcurrentModificationException.
  • ConcurrentHashMap does not allow null as a key or a value.
  • The default concurrency-level of ConcurrentHashMap is 16, that is 16 threads can simultaneously update the ConcurrentHashMap.

2. Constructors

  • ConcurrentHashMap()
  • ConcurrentHashMap(int initialCapacity)
  • ConcurrentHashMap(int initialCapacity, float loadFactor)
  • ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
  • ConcurrentHashMap(Map m)

The default values for ConcurrentHashMap are:

  • initial capacity: 16
  • load factor: 0.75
  • concurrencyLevel: 16

The parameter concurrencyLevel is the the estimated number of concurrently updating threads. The implementation performs internal sizing to try to accommodate this many threads.

3. Some important methods of ConcurrentHashMap

void clear()Removes all of the mappings from this map.
boolean containsKey(Object key)Checks if the specified object is a key in this table.
V get(Object key)Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
boolean isEmpty()Returns true if this map contains no key-value mappings.
V put(K key, V value)Maps the specified key to the specified value in this table.
V remove(Object key)Removes the key (and its corresponding value) from this map.
int size()Returns the number of key-value mappings in this map.
Collection values()Returns a Collection view of the values contained in this map.

4. Example of ConcurrentHashMap common operations

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
	public static void main(String[] args) throws IOException {
		ConcurrentHashMap cmap = new ConcurrentHashMap();
		// add values
		cmap.put("one", "1");
		cmap.put("two", "2");
		cmap.put("three", "3");

		System.out.println(cmap); // {one=1, two=2, three=3}

		// remove a value
		cmap.remove("two");

		System.out.println(cmap); // {one=1, three=3}

		// replace a value
		cmap.replace("one", "new value");

		System.out.println(cmap); // {one=new value, three=3}

		// size of map
		System.out.println(cmap.size()); // 2

		// value of map
		System.out.println(cmap.values()); // [new value, 3]

		// check if map is empty
		System.out.println(cmap.isEmpty()); // false

		// check if map contains a key
		System.out.println(cmap.containsKey("one")); // true

		// clear the map
		cmap.clear();

		System.out.println(cmap); // {}

	}
}

5. Example of simultaneous read and write in ConcurrentHashMap

In this example, we’ll create a ConcurrentHashMap with one key. We’ll create two threads, one to update the value and the other to read the value. We’ll use a loop to read and write values simultaneously.

import java.util.concurrent.ConcurrentHashMap;

class MyThreadWrite implements Runnable {
	ConcurrentHashMap cmap;

	public MyThreadWrite(ConcurrentHashMap cmap) {
		super();
		this.cmap = cmap;
	}

	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + " running. Writing value: " + i);
			cmap.put("one", i);
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class MyThreadRead implements Runnable {
	ConcurrentHashMap cmap;

	public MyThreadRead(ConcurrentHashMap cmap) {
		super();
		this.cmap = cmap;
	}

	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + " Running. Reading Value: " + this.cmap.get("one"));
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class ConcurrentHashMapExample2 {
	public static void main(String args[]) {
		ConcurrentHashMap cmap = new ConcurrentHashMap();

		Thread t1 = new Thread(new MyThreadRead(cmap));
		Thread t2 = new Thread(new MyThreadWrite(cmap));
		t1.start();
		t2.start();
	}
}

Output

Thread-0 Running. Reading Value: null
Thread-1 running. Writing value: 0
Thread-0 Running. Reading Value: 0
Thread-1 running. Writing value: 1
Thread-1 running. Writing value: 2
Thread-0 Running. Reading Value: 2
Thread-1 running. Writing value: 3
Thread-0 Running. Reading Value: 2
Thread-0 Running. Reading Value: 3
Thread-1 running. Writing value: 4
Thread-0 Running. Reading Value: 4
...........................