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 injava.util.concurrent
package. This class is a member of the Java Collections Framework. This class implementsSerializable
,ConcurrentMap
andMap
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
andremove
. 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 allownull
as a key or a value.- The default concurrency-level of
ConcurrentHashMap
is 16, that is 16 threads can simultaneously update theConcurrentHashMap
.
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 ...........................