commit
b5fb4b4182
|
@ -0,0 +1,43 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung.concurrent.lock</groupId>
|
||||
<artifactId>core-java-concurrency-collections-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<jmh.version>1.21</jmh.version>
|
||||
<guava.version>28.2-jre</guava.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.concurrent.lock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
|
||||
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.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
@State(Scope.Thread)
|
||||
@Fork(value = 2)
|
||||
@Warmup(iterations = 0)
|
||||
public class ConcurrentAccessBenchmark {
|
||||
static final int SLOTS = 4;
|
||||
static final int THREADS = 10000;
|
||||
static final int BUCKETS = Runtime.getRuntime().availableProcessors() * SLOTS;
|
||||
SingleLock singleLock = new SingleLock();
|
||||
StripedLock stripedLock = new StripedLock(BUCKETS);
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public Map<String,String> singleLockHashMap() throws InterruptedException {
|
||||
return singleLock.doWork(new HashMap<String,String>(), THREADS, SLOTS);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public Map<String,String> stripedLockHashMap() throws InterruptedException {
|
||||
return stripedLock.doWork(new HashMap<String,String>(), THREADS, SLOTS);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public Map<String,String> singleLockConcurrentHashMap() throws InterruptedException {
|
||||
return singleLock.doWork(new ConcurrentHashMap<String,String>(), THREADS, SLOTS);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public Map<String,String> stripedLockConcurrentHashMap() throws InterruptedException {
|
||||
return stripedLock.doWork(new ConcurrentHashMap<String,String>(), THREADS, SLOTS);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.concurrent.lock;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
public abstract class ConcurrentAccessExperiment {
|
||||
|
||||
public final Map<String,String> doWork(Map<String,String> map, int threads, int slots) {
|
||||
CompletableFuture<?>[] requests = new CompletableFuture<?>[threads * slots];
|
||||
|
||||
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();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected abstract Supplier<?> putSupplier(Map<String,String> map, int key);
|
||||
protected abstract Supplier<?> getSupplier(Map<String,String> map, int key);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.concurrent.lock;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
public class SingleLock extends ConcurrentAccessExperiment {
|
||||
ReentrantLock lock;
|
||||
|
||||
public SingleLock() {
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
protected Supplier<?> putSupplier(Map<String,String> map, int key) {
|
||||
return (()-> {
|
||||
lock.lock();
|
||||
try {
|
||||
return map.put("key" + key, "value" + key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Supplier<?> getSupplier(Map<String,String> map, int key) {
|
||||
return (()-> {
|
||||
lock.lock();
|
||||
try {
|
||||
return map.get("key" + key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package 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 ConcurrentAccessExperiment {
|
||||
Striped<Lock> stripedLock;
|
||||
|
||||
public StripedLock(int buckets) {
|
||||
stripedLock = Striped.lock(buckets);
|
||||
}
|
||||
|
||||
protected Supplier<?> putSupplier(Map<String,String> map, int key) {
|
||||
return (()-> {
|
||||
int bucket = key % stripedLock.size();
|
||||
Lock lock = stripedLock.get(bucket);
|
||||
lock.lock();
|
||||
try {
|
||||
return map.put("key" + key, "value" + key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Supplier<?> getSupplier(Map<String,String> map, int key) {
|
||||
return (()-> {
|
||||
int bucket = key % stripedLock.size();
|
||||
Lock lock = stripedLock.get(bucket);
|
||||
lock.lock();
|
||||
try {
|
||||
return map.get("key" + key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue