Skip to content

Commit b5fb4b4

Browse files
authored
Merge pull request #8758 from mguarnaccia/BAEL-3855
BAEL-3855
2 parents 76b091a + 0692bac commit b5fb4b4

5 files changed

Lines changed: 200 additions & 0 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<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">
2+
<modelVersion>4.0.0</modelVersion>
3+
<groupId>com.baeldung.concurrent.lock</groupId>
4+
<artifactId>core-java-concurrency-collections-2</artifactId>
5+
<version>0.0.1-SNAPSHOT</version>
6+
7+
<properties>
8+
<jmh.version>1.21</jmh.version>
9+
<guava.version>28.2-jre</guava.version>
10+
</properties>
11+
12+
<dependencies>
13+
<dependency>
14+
<groupId>com.google.guava</groupId>
15+
<artifactId>guava</artifactId>
16+
<version>${guava.version}</version>
17+
</dependency>
18+
<dependency>
19+
<groupId>org.openjdk.jmh</groupId>
20+
<artifactId>jmh-core</artifactId>
21+
<version>${jmh.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.openjdk.jmh</groupId>
25+
<artifactId>jmh-generator-annprocess</artifactId>
26+
<version>${jmh.version}</version>
27+
</dependency>
28+
29+
</dependencies>
30+
<build>
31+
<sourceDirectory>src</sourceDirectory>
32+
<plugins>
33+
<plugin>
34+
<artifactId>maven-compiler-plugin</artifactId>
35+
<version>3.8.0</version>
36+
<configuration>
37+
<source>1.8</source>
38+
<target>1.8</target>
39+
</configuration>
40+
</plugin>
41+
</plugins>
42+
</build>
43+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.baeldung.concurrent.lock;
2+
3+
import java.util.HashMap;
4+
import java.util.concurrent.ConcurrentHashMap;
5+
import java.util.concurrent.TimeUnit;
6+
import java.util.Map;
7+
8+
import org.openjdk.jmh.annotations.Benchmark;
9+
import org.openjdk.jmh.annotations.BenchmarkMode;
10+
import org.openjdk.jmh.annotations.Fork;
11+
import org.openjdk.jmh.annotations.Mode;
12+
import org.openjdk.jmh.annotations.OutputTimeUnit;
13+
import org.openjdk.jmh.annotations.Scope;
14+
import org.openjdk.jmh.annotations.State;
15+
import org.openjdk.jmh.annotations.Warmup;
16+
17+
@State(Scope.Thread)
18+
@Fork(value = 2)
19+
@Warmup(iterations = 0)
20+
public class ConcurrentAccessBenchmark {
21+
static final int SLOTS = 4;
22+
static final int THREADS = 10000;
23+
static final int BUCKETS = Runtime.getRuntime().availableProcessors() * SLOTS;
24+
SingleLock singleLock = new SingleLock();
25+
StripedLock stripedLock = new StripedLock(BUCKETS);
26+
27+
@Benchmark
28+
@BenchmarkMode(Mode.Throughput)
29+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
30+
public Map<String,String> singleLockHashMap() throws InterruptedException {
31+
return singleLock.doWork(new HashMap<String,String>(), THREADS, SLOTS);
32+
}
33+
34+
@Benchmark
35+
@BenchmarkMode(Mode.Throughput)
36+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
37+
public Map<String,String> stripedLockHashMap() throws InterruptedException {
38+
return stripedLock.doWork(new HashMap<String,String>(), THREADS, SLOTS);
39+
}
40+
41+
@Benchmark
42+
@BenchmarkMode(Mode.Throughput)
43+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
44+
public Map<String,String> singleLockConcurrentHashMap() throws InterruptedException {
45+
return singleLock.doWork(new ConcurrentHashMap<String,String>(), THREADS, SLOTS);
46+
}
47+
48+
@Benchmark
49+
@BenchmarkMode(Mode.Throughput)
50+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
51+
public Map<String,String> stripedLockConcurrentHashMap() throws InterruptedException {
52+
return stripedLock.doWork(new ConcurrentHashMap<String,String>(), THREADS, SLOTS);
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.baeldung.concurrent.lock;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.CompletableFuture;
5+
6+
import com.google.common.base.Supplier;
7+
8+
public abstract class ConcurrentAccessExperiment {
9+
10+
public final Map<String,String> doWork(Map<String,String> map, int threads, int slots) {
11+
CompletableFuture<?>[] requests = new CompletableFuture<?>[threads * slots];
12+
13+
for (int i = 0; i < threads; i++) {
14+
requests[slots * i + 0] = CompletableFuture.supplyAsync(putSupplier(map, i));
15+
requests[slots * i + 1] = CompletableFuture.supplyAsync(getSupplier(map, i));
16+
requests[slots * i + 2] = CompletableFuture.supplyAsync(getSupplier(map, i));
17+
requests[slots * i + 3] = CompletableFuture.supplyAsync(getSupplier(map, i));
18+
}
19+
CompletableFuture.allOf(requests).join();
20+
21+
return map;
22+
}
23+
24+
protected abstract Supplier<?> putSupplier(Map<String,String> map, int key);
25+
protected abstract Supplier<?> getSupplier(Map<String,String> map, int key);
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.baeldung.concurrent.lock;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.locks.ReentrantLock;
5+
6+
import com.google.common.base.Supplier;
7+
8+
public class SingleLock extends ConcurrentAccessExperiment {
9+
ReentrantLock lock;
10+
11+
public SingleLock() {
12+
lock = new ReentrantLock();
13+
}
14+
15+
protected Supplier<?> putSupplier(Map<String,String> map, int key) {
16+
return (()-> {
17+
lock.lock();
18+
try {
19+
return map.put("key" + key, "value" + key);
20+
} finally {
21+
lock.unlock();
22+
}
23+
});
24+
}
25+
26+
protected Supplier<?> getSupplier(Map<String,String> map, int key) {
27+
return (()-> {
28+
lock.lock();
29+
try {
30+
return map.get("key" + key);
31+
} finally {
32+
lock.unlock();
33+
}
34+
});
35+
}
36+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.baeldung.concurrent.lock;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.locks.Lock;
5+
6+
import com.google.common.base.Supplier;
7+
import com.google.common.util.concurrent.Striped;
8+
9+
public class StripedLock extends ConcurrentAccessExperiment {
10+
Striped<Lock> stripedLock;
11+
12+
public StripedLock(int buckets) {
13+
stripedLock = Striped.lock(buckets);
14+
}
15+
16+
protected Supplier<?> putSupplier(Map<String,String> map, int key) {
17+
return (()-> {
18+
int bucket = key % stripedLock.size();
19+
Lock lock = stripedLock.get(bucket);
20+
lock.lock();
21+
try {
22+
return map.put("key" + key, "value" + key);
23+
} finally {
24+
lock.unlock();
25+
}
26+
});
27+
}
28+
29+
protected Supplier<?> getSupplier(Map<String,String> map, int key) {
30+
return (()-> {
31+
int bucket = key % stripedLock.size();
32+
Lock lock = stripedLock.get(bucket);
33+
lock.lock();
34+
try {
35+
return map.get("key" + key);
36+
} finally {
37+
lock.unlock();
38+
}
39+
});
40+
}
41+
}

0 commit comments

Comments
 (0)