diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/BenchMark.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/BenchMark.java index 438bcb2f4b..5d9e382351 100644 --- a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/BenchMark.java +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/BenchMark.java @@ -1,13 +1,9 @@ -package com.baeldung.concurrent.lock; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +package main.java.com.baeldung.concurrent.lock; 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.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; @@ -17,45 +13,36 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; @State(Scope.Thread) -@Fork(value = 2) -@Warmup(iterations = 3) +@Fork(value = 1) +@Warmup(iterations = 0) public class BenchMark { ConcurrentAccessMap accessMyMap; + static final int SLOTS = 4; + static final int THREADS = 1000; + static final int BUCKETS = Runtime.getRuntime().availableProcessors() * SLOTS; - @Param({"HashMap with Lock", "HashMap with Striped Lock", - "ConcurrentHashMap with Lock", "ConcurrentHashMap with Striped Lock"}) - private String type; + @Param({"Single Lock", "Striped Lock"}) + private String lockType; + @Param({"HashMap", "ConcurrentHashMap"}) + private String mapType; + @Setup public void setup() { - switch (type) { - case "HashMap with Lock": - accessMyMap = new CoarseGrained(getHashMap()); + switch (lockType) { + case "Single Lock": + accessMyMap = new SingleLock(); break; - case "ConcurrentHashMap with Lock": - accessMyMap = new CoarseGrained(getConcurrentHashMap()); - break; - case "HashMap with Striped Lock": - accessMyMap = new LockStriped(getHashMap()); - break; - case "ConcurrentHashMap with Striped Lock": - accessMyMap = new LockStriped(getConcurrentHashMap()); + case "Striped Lock": + accessMyMap = new StripedLock(BUCKETS); break; } } - private Map getHashMap() { - return new HashMap(); - } - - private Map getConcurrentHashMap() { - return new ConcurrentHashMap(); - } - @Benchmark @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public void test() throws InterruptedException { - accessMyMap.doWork(type); + accessMyMap.doWork(mapType, THREADS, SLOTS); } } diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessMap.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessMap.java index 00b61cdc09..e5fcd6d406 100644 --- a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessMap.java +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessMap.java @@ -1,33 +1,48 @@ -package com.baeldung.concurrent.lock; +package main.java.com.baeldung.concurrent.lock; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import com.google.common.base.Supplier; public abstract class ConcurrentAccessMap { - static final int SLOTS = 4; - static final int THREADS = 10000; - static final int BUCKETS = Runtime.getRuntime().availableProcessors() * SLOTS; - private CompletableFuture[] requests; - protected Map map; - public ConcurrentAccessMap(Map map) { - this.map = map; + public ConcurrentAccessMap() { + } + + private Map getHashMap() { + return new HashMap(); } - public final void doWork(String type) { - requests = new CompletableFuture[THREADS * SLOTS]; + private Map getConcurrentHashMap() { + return new ConcurrentHashMap(); + } + + private Map setup(String type) { + switch (type) { + case "HashMap": + return getHashMap(); + case "ConcurrentHashMap": + return getConcurrentHashMap(); + } + return null; + } - for (int i = 0; i < THREADS; i++) { - requests[SLOTS * i + 0] = CompletableFuture.supplyAsync(putSupplier(i)); - requests[SLOTS * i + 1] = CompletableFuture.supplyAsync(getSupplier(i)); - requests[SLOTS * i + 2] = CompletableFuture.supplyAsync(getSupplier(i)); - requests[SLOTS * i + 3] = CompletableFuture.supplyAsync(getSupplier(i)); - } + public final void doWork(String type, int threads, int slots) { + CompletableFuture[] requests = new CompletableFuture[threads * slots]; + Map map = setup(type); + + for (int i = 0; i < threads; i++) { + requests[slots * i + 0] = CompletableFuture.supplyAsync(putSupplier(map, i)); + requests[slots * i + 1] = CompletableFuture.supplyAsync(getSupplier(map, i)); + requests[slots * i + 2] = CompletableFuture.supplyAsync(getSupplier(map, i)); + requests[slots * i + 3] = CompletableFuture.supplyAsync(getSupplier(map, i)); + } CompletableFuture.allOf(requests).join(); } - protected abstract Supplier putSupplier(int x); - protected abstract Supplier getSupplier(int x); + protected abstract Supplier putSupplier(Map map, int key); + protected abstract Supplier getSupplier(Map map, int key); } \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/SingleLock.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/SingleLock.java new file mode 100644 index 0000000000..4f0fe0222a --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/SingleLock.java @@ -0,0 +1,38 @@ +package main.java.com.baeldung.concurrent.lock; + +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import com.google.common.base.Supplier; + +public class SingleLock extends ConcurrentAccessMap { + ReentrantLock lock; + + public SingleLock() { + lock = new ReentrantLock(); + } + + protected synchronized Supplier putSupplier(Map map, int key) { + return (()-> { + boolean done = false; + while(!done) { + done = lock.tryLock(); + } + map.put("key" + key, "value" + key); + lock.unlock(); + return null; + }); + } + + protected synchronized Supplier getSupplier(Map map, int key) { + return (()-> { + boolean done = false; + while(!done) { + done = lock.tryLock(); + } + map.get("key" + key); + lock.unlock(); + return null; + }); + } +} diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/StripedLock.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/StripedLock.java new file mode 100644 index 0000000000..fe98dd82be --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/StripedLock.java @@ -0,0 +1,46 @@ +package main.java.com.baeldung.concurrent.lock; + +import java.util.Map; +import java.util.concurrent.locks.Lock; + +import com.google.common.base.Supplier; +import com.google.common.util.concurrent.Striped; + +public class StripedLock extends ConcurrentAccessMap { + Striped lock; + + public StripedLock(int buckets) { + lock = getStripedLock(buckets); + } + + private Striped getStripedLock(int buckets) { + Striped map = Striped.lock(buckets); + return map; + } + + protected synchronized Supplier putSupplier(Map map, int key) { + return (()-> { + Lock currentLock = lock.get("key" + key); + boolean done = false; + while(!done) { + done = currentLock.tryLock(); + } + map.put("key" + key, "value" + key); + currentLock.unlock(); + return null; + }); + } + + protected synchronized Supplier getSupplier(Map map, int key) { + return (()-> { + Lock currentLock = lock.get("key" + key); + boolean done = false; + while(!done) { + done = currentLock.tryLock(); + } + map.get("key" + key); + currentLock.unlock(); + return null; + }); + } +}