diff --git a/core-java/src/test/java/com/baeldung/java/concurrentmap/ConcurrentNavigableMapTests.java b/core-java/src/test/java/com/baeldung/java/concurrentmap/ConcurrentNavigableMapTests.java new file mode 100644 index 0000000000..93087626a4 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java/concurrentmap/ConcurrentNavigableMapTests.java @@ -0,0 +1,79 @@ +package com.baeldung.java.concurrentmap; + +import org.junit.Test; + +import java.util.Iterator; +import java.util.NavigableMap; +import java.util.TreeMap; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.testng.Assert.*; + +public class ConcurrentNavigableMapTests { + + @Test + public void givenSkipListMap_whenAccessInMultiThreads_thenOrderingStable() throws InterruptedException { + NavigableMap skipListMap = new ConcurrentSkipListMap<>(); + + updateMapConcurrently(skipListMap, 4); + + Iterator skipListIter = skipListMap + .keySet() + .iterator(); + int previous = skipListIter.next(); + while (skipListIter.hasNext()) { + int current = skipListIter.next(); + assertTrue(previous < current); + } + } + + private void updateMapConcurrently(NavigableMap navigableMap, int concurrencyLevel) throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel); + for (int i = 0; i < concurrencyLevel; i++) { + executorService.execute(() -> { + ThreadLocalRandom random = ThreadLocalRandom.current(); + for (int j = 0; j < 10000; j++) { + navigableMap.put(random.nextInt(), "test"); + } + }); + } + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.MINUTES); + } + + @Test + public void givenSkipListMap_whenNavConcurrently_thenCountCorrect() throws InterruptedException { + NavigableMap skipListMap = new ConcurrentSkipListMap<>(); + int count = countMapElementByPollingFirstEntry(skipListMap, 10000, 4); + assertEquals(10000 * 4, count); + } + + @Test + public void givenTreeMap_whenNavConcurrently_thenCountError() throws InterruptedException { + NavigableMap treeMap = new TreeMap<>(); + int count = countMapElementByPollingFirstEntry(treeMap, 10000, 4); + assertNotEquals(10000 * 4, count); + } + + private int countMapElementByPollingFirstEntry(NavigableMap navigableMap, int elementCount, int concurrencyLevel) throws InterruptedException { + for (int i = 0; i < elementCount * concurrencyLevel; i++) { + navigableMap.put(i, i); + } + AtomicInteger counter = new AtomicInteger(0); + ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel); + for (int j = 0; j < concurrencyLevel; j++) { + executorService.execute(() -> { + for (int i = 0; i < elementCount; i++) { + if (navigableMap.pollFirstEntry() != null) { + counter.incrementAndGet(); + } + } + }); + } + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.MINUTES); + return counter.get(); + } + +}