![](/img/trans.png)
[英]What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map)?
[英]What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map) in term of performance?
我試圖通過使用代碼來評估這些概念。 這就是我最終的結果
public void runCWith3Threads() {
// mesure add with 3 threads
for (int i = 0; i < 10; i++) {
Map<Integer, Person> shm = Collections.synchronizedMap(new HashMap<Integer, Person>());
Map<Integer, Person> chm = new ConcurrentHashMap<Integer, Person>();
MapThread sm1 = new MapThread(shm, 0, 20000, "sm1");
MapThread sm2 = new MapThread(shm, 20000, 30000, "sm2");
MapThread sm3 = new MapThread(shm, 30000, 50000, "sm3");
sm1.start();sm2.start();sm3.start();
while (true) {
try {
sm1.join();
sm2.join();
sm3.join();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long secondMax = sm1.time > sm2.time ? sm1.time : sm2.time;
long firstMax = secondMax > sm3.time ? secondMax : sm3.time;
System.out.println("Millisec of SynchronizedMap cost: " + firstMax);
MapThread m1 = new MapThread(chm, 0, 20000, "m1");
MapThread m2 = new MapThread(chm, 20000, 30000, "m2");
MapThread m3 = new MapThread(chm, 30000, 50000, "m3");
m1.start();m2.start();m3.start();
while (true) {
try {
m1.join();
m2.join();
m3.join();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
secondMax = m1.time > m2.time ? m1.time : m2.time;
firstMax = secondMax > m3.time ? secondMax : m3.time;
System.out.println("Millisec of ConcurrentHashMap cost: " + firstMax);
System.out.println();
}
}
public class MapThread extends Thread {
Map<Integer, Person> map;
int from;
int to;
long time;
String name;
public MapThread(Map<Integer, Person> map, int from, int to, String name) {
this.map = map;
this.from = from;
this.to = to;
this.name = name;
}
public void run() {
long start = System.currentTimeMillis();
for (int i = from; i < to; i++) {
map.put(i, new Person());
}
long end = System.currentTimeMillis();
time = end - start;
return;
}
}
我期望的是,在代碼運行之后, ConcurrentHashMap
的結果會更快,因為它允許多次插入到地圖中。 對於SynchronizedMap
,由於每個線程都在等待前一個線程完成(映射已同步),因此一旦運行單個線程環境,代碼就會起到相同作用
但是,結果並沒有完全反映出我的預期
Millisec of SynchronizedMap cost: 250
Millisec of ConcurrentHashMap cost: 203
Millisec of SynchronizedMap cost: 171
Millisec of ConcurrentHashMap cost: 172
Millisec of SynchronizedMap cost: 172
Millisec of ConcurrentHashMap cost: 188
Millisec of SynchronizedMap cost: 171
Millisec of ConcurrentHashMap cost: 172
Millisec of SynchronizedMap cost: 187
Millisec of ConcurrentHashMap cost: 172
Millisec of SynchronizedMap cost: 171
Millisec of ConcurrentHashMap cost: 189
Millisec of SynchronizedMap cost: 187
Millisec of ConcurrentHashMap cost: 171
Millisec of SynchronizedMap cost: 188
Millisec of ConcurrentHashMap cost: 171
Millisec of SynchronizedMap cost: 172
Millisec of ConcurrentHashMap cost: 172
Millisec of SynchronizedMap cost: 171
Millisec of ConcurrentHashMap cost: 188
這是為什么 ?
更新
Map<Integer, Person> chm = new ConcurrentHashMap<Integer, Person>(100000, 10, 3);
我有結果
Millisec of SynchronizedMap cost: 208
Millisec of ConcurrentHashMap cost: 216
Millisec of SynchronizedMap cost: 255
Millisec of ConcurrentHashMap cost: 196
Map<Integer, Person> chm = new ConcurrentHashMap<Integer, Person>(100000);
我有結果
Millisec of SynchronizedMap cost: 204
Millisec of ConcurrentHashMap cost: 283
Millisec of SynchronizedMap cost: 203
Millisec of ConcurrentHashMap cost: 200
如果您正在進行基准測試,您應該:
如果我創建類似於您的基准測試的基准測試,我會得到以下結果:
Warmup...
Benchmark...
4 * 500000: 0.22s / 0.04s
4 * 1000000: 0.55s / 0.10s
4 * 1500000: 1.10s / 0.16s
4 * 2000000: 0.90s / 0.19s
4 * 2500000: 1.68s / 0.25s
第一個數字表示線程數,第二個數字表示int范圍的大小,第三個數字表示同步Map的持續時間,第四個數字表示ConcurrentHashMap的持續時間。 如您所見, ConcurrentHashMap在所有情況下都明顯更快。
您可以在下面找到整個Java代碼。 請注意,它使用了Java 8中的功能。但是,這應該對結果沒有影響:
public static void main(String... args) {
System.out.println("Warmup...");
for (int i = 0; i < 10000; ++i) {
test(Collections.synchronizedMap(new HashMap<>()), 2, 1000);
test(new ConcurrentHashMap<>(), 2, 1000);
}
System.out.println("Benchmark...");
for (int i = 0; i < 5; ++i) {
int threads = 4;
int range = 500000 * (i + 1);
System.out.printf("%2d * %7d: %s / %s\n",
threads, range,
test(Collections.synchronizedMap(new HashMap<>()), threads, range),
test(new ConcurrentHashMap<>(), threads, range));
}
}
public static String test(Map<Integer,Object> map, int threads, int range) {
long duration = IntStream.range(0, 10)
.mapToLong(i -> execute(
IntStream.range(0, threads)
.<Runnable>mapToObj(t -> () -> bulkPut(map, t * range, (t + 1) * range, new Object()))
.toArray(Runnable[]::new)))
.min().getAsLong();
return String.format("%4.2fs",
duration / 1000.0, threads, range);
}
public static <T> void bulkPut(Map<Integer,T> map, int from, int to, T value) {
for (int i = from; i < to; ++i) {
map.put(i, value);
}
}
public static long execute(Runnable... runnables) {
List<Thread> threads = new ArrayList<>();
AtomicLong duration = new AtomicLong();
for (Runnable runnable : runnables) {
Thread thread = new Thread(() -> {
long start = System.currentTimeMillis();
try {
runnable.run();
} finally {
long elapsed = System.currentTimeMillis() - start;
duration.accumulateAndGet(elapsed, Math::max);
}
});
thread.start();
threads.add(thread);
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return duration.get();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.