From aaac4e6a95e5e274c60418034e74ca1a2679a6ea Mon Sep 17 00:00:00 2001 From: Amitabh Tiwari Date: Mon, 23 Nov 2020 09:56:16 +0530 Subject: [PATCH] Added changes to fix the details --- ...oncurrentHashMapVsSynchronizedMapTest.java | 159 ++++++++++++++++++ .../ConcurrentModificationErrorTest.java | 41 +++++ .../cuncurrenthashmap/PerformanceTest.java | 54 ++++++ .../map/cuncurrenthashmap/UserId.java | 17 ++ 4 files changed, 271 insertions(+) create mode 100644 core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentHashMapVsSynchronizedMapTest.java create mode 100644 core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentModificationErrorTest.java create mode 100644 core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/PerformanceTest.java create mode 100644 core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/UserId.java diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentHashMapVsSynchronizedMapTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentHashMapVsSynchronizedMapTest.java new file mode 100644 index 0000000000..6a7716d38a --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentHashMapVsSynchronizedMapTest.java @@ -0,0 +1,159 @@ +package com.baeldung.map.cuncurrenthashmap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.junit.Assert; +import org.junit.Test; + +public class ConcurrentHashMapVsSynchronizedMapTest { + + public final static int THREAD_POOL_SIZE = 5; + public final static int TEST_ITERATIONS = 5; + public final static int TEST_NO_ITEMS = 500000; + + @Test + public void randomReadAndWritePerformaceTest_cuncurrentHashMap_faster() + throws InterruptedException { + // For synchronizedMap + Long totalTimeForSynchronizedMap = 0l; + Map slowerMap = Collections + .synchronizedMap(new HashMap()); + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForSynchronizedMap += performReadAndWriteTest(slowerMap); + } + Long avgTimeForSynchronizedMap = totalTimeForSynchronizedMap / TEST_ITERATIONS; + + // For ConcurrentHashMap Object + Long totalTimeForCuncurrentHashMap = 0l; + Map fasterMap = new ConcurrentHashMap<>(); + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForCuncurrentHashMap += performReadAndWriteTest(fasterMap); + } + Long avgTimeForCuncurrentHashMap = totalTimeForCuncurrentHashMap / TEST_ITERATIONS; + + Assert.assertTrue(avgTimeForSynchronizedMap > avgTimeForCuncurrentHashMap); + } + + @Test + public void randomWritePerformaceTest_cuncurrentHashMap_faster() throws InterruptedException { + // For synchronizedMap + Long totalTimeForSynchronizedMap = 0l; + Map slowerMap = Collections + .synchronizedMap(new HashMap()); + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForSynchronizedMap += performWriteTest(slowerMap); + } + Long avgTimeForSynchronizedMap = totalTimeForSynchronizedMap / TEST_ITERATIONS; + + // For ConcurrentHashMap Object + Long totalTimeForCuncurrentHashMap = 0l; + Map fasterMap = new ConcurrentHashMap<>(); + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForCuncurrentHashMap += performWriteTest(fasterMap); + } + Long avgTimeForCuncurrentHashMap = totalTimeForCuncurrentHashMap / TEST_ITERATIONS; + + Assert.assertTrue(avgTimeForSynchronizedMap > avgTimeForCuncurrentHashMap); + } + + @Test + public void randomReadPerformaceTest_cuncurrentHashMap_faster() throws InterruptedException { + + Map slowerMap = Collections + .synchronizedMap(addItems(new HashMap())); + // For synchronizedMap + Long totalTimeForSynchronizedMap = 0l; + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForSynchronizedMap += performReadTest(slowerMap); + } + Long avgTimeForSynchronizedMap = totalTimeForSynchronizedMap / TEST_ITERATIONS; + + Map fasterMap = Collections + .synchronizedMap(addItems(new ConcurrentHashMap())); + // For ConcurrentHashMap Object + Long totalTimeForCuncurrentHashMap = 0l; + new ConcurrentHashMap<>(); + for (int i = 0; i < TEST_ITERATIONS; i++) { + totalTimeForCuncurrentHashMap += performReadTest(fasterMap); + } + Long avgTimeForCuncurrentHashMap = totalTimeForCuncurrentHashMap / TEST_ITERATIONS; + + Assert.assertTrue(avgTimeForSynchronizedMap > avgTimeForCuncurrentHashMap); + } + + private Map addItems(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); + } + return map; + } + + private long performWriteTest(final Map map) throws InterruptedException { + long startTime = System.nanoTime(); + ExecutorService exectures = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + for (int j = 0; j < THREAD_POOL_SIZE; j++) { + exectures.execute(new Runnable() { + @Override + public void run() { + 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); + } + } + }); + } + exectures.shutdown(); + exectures.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + long entTime = System.nanoTime(); + return (entTime - startTime) / 1000000L; + } + + private long performReadAndWriteTest(final Map map) + throws InterruptedException { + long startTime = System.nanoTime(); + ExecutorService exectures = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + for (int j = 0; j < THREAD_POOL_SIZE; j++) { + exectures.execute(new Runnable() { + @Override + public void run() { + for (int i = 0; i < TEST_NO_ITEMS; i++) { + Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS); + Integer value = map.get(String.valueOf(randNumber)); + map.put(String.valueOf(randNumber), randNumber); + } + } + }); + } + exectures.shutdown(); + exectures.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + long entTime = System.nanoTime(); + return (entTime - startTime) / 1000000L; + } + + private long performReadTest(final Map map) throws InterruptedException { + long startTime = System.nanoTime(); + ExecutorService exectures = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + for (int j = 0; j < THREAD_POOL_SIZE; j++) { + exectures.execute(new Runnable() { + @Override + public void run() { + for (int i = 0; i < TEST_NO_ITEMS; i++) { + Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS); + Integer value = map.get(String.valueOf(randNumber)); + } + } + }); + } + exectures.shutdown(); + exectures.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + long entTime = System.nanoTime(); + return (entTime - startTime) / 1000000L; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentModificationErrorTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentModificationErrorTest.java new file mode 100644 index 0000000000..993354d6d0 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/ConcurrentModificationErrorTest.java @@ -0,0 +1,41 @@ +package com.baeldung.map.cuncurrenthashmap; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Assert; +import org.junit.Test; + +public class ConcurrentModificationErrorTest { + + @Test(expected = ConcurrentModificationException.class) + public void whenRemoveAndAddOnHashMap_thenCuncurrentModificationError() { + 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(4, "Modification"); + iterator.next(); + } + } + + public void whenRemoveAndAddOnCuncurrentHashMap_thenNoError() { + Map map = new ConcurrentHashMap<>(); + map.put(1, "baeldung"); + map.put(2, "HashMap"); + Iterator> iterator = map.entrySet().iterator(); + while (iterator.hasNext()) { + map.put(4, "Modification"); + iterator.next(); + } + + Assert.assertEquals(4, 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/cuncurrenthashmap/PerformanceTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/PerformanceTest.java new file mode 100644 index 0000000000..9751decf53 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/PerformanceTest.java @@ -0,0 +1,54 @@ +package com.baeldung.map.cuncurrenthashmap; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Test; + +public class PerformanceTest { + + @Test(expected = ConcurrentModificationException.class) + public void whenRemoveAndAddOnHashMap_thenCuncurrentModificationError() { + Map map = new HashMap<>(); + Map synchronizedMap = Collections.synchronizedMap(map); + long startTime = System.currentTimeMillis(); + for(int i=0; i<100000; i++) { + UserId userId = new UserId(1); + synchronizedMap.put(userId, userId.toString()); + } + long endTime = System.currentTimeMillis(); + long addTimeForSynchronized = endTime-startTime; + + startTime = System.currentTimeMillis(); + for(int i=0; i<100000; i++) { + UserId userId = new UserId(1); + synchronizedMap.get(userId); + } + endTime = System.currentTimeMillis(); + long fetchTimeForSynchronized = endTime-startTime; + + Map map1 = new ConcurrentHashMap<>(); + startTime = System.currentTimeMillis(); + for(int i=0; i<100000; i++) { + UserId userId = new UserId(1); + map1.put(userId, userId.toString()); + } + endTime = System.currentTimeMillis(); + long addTimeForConcurrent = endTime-startTime; + + startTime = System.currentTimeMillis(); + for(int i=0; i<100000; i++) { + UserId userId = new UserId(1); + map1.get(userId); + } + endTime = System.currentTimeMillis(); + long fetchTimeForConcurrent = endTime-startTime; + + System.out.println("ABC"); + + } + +} diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/UserId.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/UserId.java new file mode 100644 index 0000000000..a69976180d --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/cuncurrenthashmap/UserId.java @@ -0,0 +1,17 @@ +package com.baeldung.map.cuncurrenthashmap; + +public class UserId { + + private int id; + + public UserId(int id) { + super(); + this.id = id; + } + + @Override + public int hashCode() { + return this.id%10; + } + +}