diff --git a/core-java-modules/core-java-collections-maps-3/pom.xml b/core-java-modules/core-java-collections-maps-3/pom.xml
index f547968b22..577ad58255 100644
--- a/core-java-modules/core-java-collections-maps-3/pom.xml
+++ b/core-java-modules/core-java-collections-maps-3/pom.xml
@@ -15,7 +15,11 @@
-
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh-core.version}
+
diff --git a/core-java-modules/core-java-collections-maps-3/src/main/java/com/baeldung/map/concurrenthashmap/MapPerformanceComparison.java b/core-java-modules/core-java-collections-maps-3/src/main/java/com/baeldung/map/concurrenthashmap/MapPerformanceComparison.java
new file mode 100644
index 0000000000..c788dbc27d
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-3/src/main/java/com/baeldung/map/concurrenthashmap/MapPerformanceComparison.java
@@ -0,0 +1,96 @@
+package com.baeldung.map.concurrenthashmap;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Fork(5)
+@Threads(10)
+@Warmup(iterations = 5)
+@State(Scope.Benchmark)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class MapPerformanceComparison {
+
+ private int TEST_NO_ITEMS;
+
+ public static void main(String[] args) throws Exception {
+ org.openjdk.jmh.Main.main(args);
+ }
+
+ @Setup
+ public void setup() {
+ TEST_NO_ITEMS = 1000;
+ }
+
+ @Benchmark
+ public void randomReadAndWriteSynchronizedMap() {
+ Map map = Collections.synchronizedMap(new HashMap());
+ performReadAndWriteTest(map);
+ }
+
+ @Benchmark
+ public void randomReadAndWriteConcurrentHashMap() {
+ Map map = new ConcurrentHashMap<>();
+ performReadAndWriteTest(map);
+ }
+
+ private void performReadAndWriteTest(final Map map) {
+ for (int i = 0; i < TEST_NO_ITEMS; i++) {
+ Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS);
+ map.get(String.valueOf(randNumber));
+ map.put(String.valueOf(randNumber), randNumber);
+ }
+ }
+
+ @Benchmark
+ public void randomWriteSynchronizedMap() {
+ Map map = Collections.synchronizedMap(new HashMap());
+ performWriteTest(map);
+ }
+
+ @Benchmark
+ public void randomWriteConcurrentHashMap() {
+ Map map = new ConcurrentHashMap<>();
+ performWriteTest(map);
+ }
+
+ private void performWriteTest(final Map map) {
+ for (int i = 0; i < TEST_NO_ITEMS; i++) {
+ Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS);
+ map.put(String.valueOf(randNumber), randNumber);
+ }
+ }
+
+ @Benchmark
+ public void randomReadSynchronizedMap() {
+ Map map = Collections.synchronizedMap(new HashMap());
+ performReadTest(map);
+ }
+
+ @Benchmark
+ public void randomReadConcurrentHashMap() {
+ Map map = new ConcurrentHashMap<>();
+ performReadTest(map);
+ }
+
+ private void performReadTest(final Map map) {
+ for (int i = 0; i < TEST_NO_ITEMS; i++) {
+ Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS);
+ map.get(String.valueOf(randNumber));
+ }
+ }
+}
diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/ConcurrentModificationErrorUnitTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/ConcurrentModificationErrorUnitTest.java
new file mode 100644
index 0000000000..4264e613f2
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/ConcurrentModificationErrorUnitTest.java
@@ -0,0 +1,70 @@
+package com.baeldung.map.concurrenthashmap;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ConcurrentModificationErrorUnitTest {
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void whenRemoveAndAddOnHashMap_thenConcurrentModificationError() {
+ Map map = new HashMap<>();
+ map.put(1, "baeldung");
+ map.put(2, "HashMap");
+ Map synchronizedMap = Collections.synchronizedMap(map);
+ Iterator> iterator = synchronizedMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ synchronizedMap.put(3, "Modification");
+ iterator.next();
+ }
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void whenRemoveAndAddOnTreeMap_thenConcurrentModificationError() {
+ Map map = new TreeMap<>();
+ map.put(1, "baeldung");
+ map.put(2, "HashMap");
+ Map synchronizedMap = Collections.synchronizedMap(map);
+ Iterator> iterator = synchronizedMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ synchronizedMap.put(3, "Modification");
+ iterator.next();
+ }
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void whenRemoveAndAddOnLinkedHashMap_thenConcurrentModificationError() {
+ Map map = new LinkedHashMap<>();
+ map.put(1, "baeldung");
+ map.put(2, "HashMap");
+ Map synchronizedMap = Collections.synchronizedMap(map);
+ Iterator> iterator = synchronizedMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ synchronizedMap.put(3, "Modification");
+ iterator.next();
+ }
+ }
+
+ @Test
+ public void whenRemoveAndAddOnConcurrentHashMap_thenNoError() {
+ Map map = new ConcurrentHashMap<>();
+ map.put(1, "baeldung");
+ map.put(2, "HashMap");
+ Iterator> iterator = map.entrySet().iterator();
+ while (iterator.hasNext()) {
+ map.put(3, "Modification");
+ iterator.next();
+ }
+
+ Assert.assertEquals(3, map.size());
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/NullAllowInMapUnitTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/NullAllowInMapUnitTest.java
new file mode 100644
index 0000000000..594e8ec3b4
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/concurrenthashmap/NullAllowInMapUnitTest.java
@@ -0,0 +1,73 @@
+package com.baeldung.map.concurrenthashmap;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NullAllowInMapUnitTest {
+
+ @Test
+ public void givenHashMapBackedSynchronizedMap_whenNullAsKey_thenNoError() {
+ Map map = Collections
+ .synchronizedMap(new HashMap());
+ map.put(null, 1);
+ Assert.assertTrue(map.get(null).equals(1));
+ }
+
+
+ @Test(expected = NullPointerException.class)
+ public void givenTreeMapBackedSynchronizedMap_whenNullAsKey_thenException() {
+ Map map = Collections.synchronizedMap(new TreeMap());
+ map.put(null, 1);
+ Assert.assertTrue(map.get(null).equals(1));
+ }
+
+ @Test
+ public void givenLinkedHashMapBackedSynchronizedMap_whenNullAsKey_thenNoError() {
+ Map map = Collections
+ .synchronizedMap(new LinkedHashMap());
+ map.put(null, 1);
+ Assert.assertTrue(map.get(null).equals(1));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void givenConcurrentHasMap_whenNullAsKey_thenException() {
+ Map map = new ConcurrentHashMap<>();
+ map.put(null, 1);
+ }
+
+ @Test
+ public void givenHashMapBackedSynchronizedMap_whenNullAsValue_thenNoError() {
+ Map map = Collections.synchronizedMap(new HashMap());
+ map.put("1", null);
+ Assert.assertNull(map.get("1"));
+ }
+
+ @Test
+ public void givenTreeMapBackedSynchronizedMap_whenNullAsValue_thenNoError() {
+ Map map = Collections.synchronizedMap(new TreeMap());
+ map.put("1", null);
+ Assert.assertNull(map.get("1"));
+ }
+
+ @Test
+ public void givenLinkedHashMapBackedSynchronizedMap_whenNullAsValue_thenNoError() {
+ Map map = Collections
+ .synchronizedMap(new LinkedHashMap());
+ map.put("1", null);
+ Assert.assertNull(map.get("1"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void givenConcurrentHasMap_whenNullAsValue_thenException() {
+ Map map = new ConcurrentHashMap<>();
+ map.put("1", null);
+ }
+
+}
\ No newline at end of file