Skip to content

Instantly share code, notes, and snippets.

@BewareMyPower
Created August 24, 2024 07:44
Show Gist options
  • Select an option

  • Save BewareMyPower/1083937e30cb0f5a63be74c4ee9c5559 to your computer and use it in GitHub Desktop.

Select an option

Save BewareMyPower/1083937e30cb0f5a63be74c4ee9c5559 to your computer and use it in GitHub Desktop.
Benchmark for various thread safe hash map
package org.example.benchmark;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.pulsar.common.util.collections.ConcurrentOpenHashMap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@State(Scope.Benchmark)
public class ConcurrentHashMapTest {
@State(Scope.Benchmark)
public static class BenchmarkState {
static final int numThreads = 4;
ExecutorService executor;
final List<Integer> keys = new ArrayList<>();
final List<Future<Void>> futures = new ArrayList<>();
final ConcurrentHashMap<Integer, Boolean> map = new ConcurrentHashMap<>();
final ConcurrentOpenHashMap<Integer, Boolean> map2 = ConcurrentOpenHashMap.<Integer, Boolean>newBuilder()
.build();
final Map<Integer, Boolean> map3 = Collections.synchronizedMap(new HashMap<>());
void setUp() {
final var random = new Random();
for (int i = 0; i < 10000; i++) {
keys.add(random.nextInt(100));
}
executor = Executors.newFixedThreadPool(numThreads);
}
void tearDown() {
futures.clear();
map.clear();
map2.clear();
map3.clear();
keys.clear();
executor.shutdown();
}
}
@Setup(Level.Trial)
public void setUp(BenchmarkState state) throws Exception {
state.setUp();
}
@TearDown(Level.Trial)
public void tearDown(BenchmarkState state) throws Exception {
state.tearDown();
}
@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Benchmark
public void testOfficialConcurrentHashMap(BenchmarkState state) throws Exception {
for (int i = 0; i < BenchmarkState.numThreads; i++) {
state.futures.add(state.executor.submit(() -> {
for (var key : state.keys) {
state.map.computeIfAbsent(key, __ -> true);
}
return null;
}));
}
for (var future : state.futures) {
future.get();
}
}
@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Benchmark
public void testConcurrentOpenHashMap(BenchmarkState state) throws Exception {
for (int i = 0; i < BenchmarkState.numThreads; i++) {
state.futures.add(state.executor.submit(() -> {
for (var key : state.keys) {
state.map2.computeIfAbsent(key, __ -> true);
}
return null;
}));
}
for (var future : state.futures) {
future.get();
}
}
@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Benchmark
public void testSynchronizedHashMap(BenchmarkState state) throws Exception {
for (int i = 0; i < BenchmarkState.numThreads; i++) {
state.futures.add(state.executor.submit(() -> {
for (var key : state.keys) {
state.map3.computeIfAbsent(key, __ -> true);
}
return null;
}));
}
for (var future : state.futures) {
future.get();
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(ConcurrentHashMapTest.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment