gpt4 book ai didi

java - 为什么 ConcurrentHashMap::putIfAbsent 比 ConcurrentHashMap::computeIfAbsent 快?

转载 作者:行者123 更新时间:2023-11-30 08:32:36 27 4
gpt4 key购买 nike

使用 ConcurrentHashMap,我发现 computeIfAbsent 比 putIfAbsent 慢两倍。这里是简单的测试:

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;


public class Test {
public static void main(String[] args) throws Exception {
String[] keys = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a0", "a01", "a02", "a03", "a04", "a05", "a06", "a07", "a08", "a09", "a00"};

System.out.println("Test case 1");
long time = System.currentTimeMillis();
testCase1(keys);
System.out.println("ExecutionTime: " + String.valueOf(System.currentTimeMillis() - time));

System.out.println("Test case 2");
time = System.currentTimeMillis();
testCase2(keys);
System.out.println("ExecutionTime: " + String.valueOf(System.currentTimeMillis() - time));

System.out.println("Test case 3");
time = System.currentTimeMillis();
testCase3(keys);
System.out.println("ExecutionTime: " + String.valueOf(System.currentTimeMillis() - time));
}

public static void testCase1(String[] keys) throws InterruptedException {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

List<Thread> threads = new ArrayList<>();

for (String key : keys) {
Thread thread = new Thread(() -> map.computeIfAbsent(key, s -> {
System.out.println(key);
String result = new TestRun().compute();
System.out.println("Computing finished for " + key);
return result;
}));
thread.start();
threads.add(thread);
}

for (Thread thread : threads) {
thread.join();
}
}

public static void testCase2(String[] keys) throws InterruptedException {
List<Thread> threads = new ArrayList<>();

for (String key : keys) {
Thread thread = new Thread(() -> {
System.out.println(key);
new TestRun().compute();
System.out.println("Computing finished for " + key);
});
thread.start();
threads.add(thread);
}

for (Thread thread : threads) {
thread.join();
}
}


public static void testCase3(String[] keys) throws InterruptedException {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

List<Thread> threads = new ArrayList<>();

for (String key : keys) {
Thread thread = new Thread(() -> {
Callable<String> c = () -> {
System.out.println(key);
String result = new TestRun().compute();
System.out.println("Computing finished for " + key);
return result;
};

try {
map.putIfAbsent(key, c.call());
} catch (Exception e) {
e.printStackTrace(System.out);
}
});
thread.start();
threads.add(thread);
}

for (Thread thread : threads) {
thread.join();
}
}

}

class TestRun {
public String compute() {
try {
Thread.currentThread().sleep(5000);
} catch (Exception e) {
e.printStackTrace(System.out);
}
return UUID.randomUUID().toString();
}
}

在我的笔记本电脑上运行这个测试,testCase1(使用 computeIfAbsent())的执行时间是 10068ms,testCase2(执行相同的东西但没有将其包装到 computeIfAbsent())的执行时间是 5009ms(当然它会有所不同有点,但主要趋势就是这样)。最有趣的是 testCase3 - 它与 testCase1 几乎相同(除了使用 putIfAbsent() 而不是 computeIfAbsent()),但它的执行速度快了两倍(testCase3 为 5010ms,testCase1 为 10068ms)。

查看源代码,computeIfAbsent() 和 putVal()(在底层的 putIfAbsent() 中使用)几乎相同。

有人知道是什么导致线程执行时间不同吗?

最佳答案

您遇到记录的功能:

Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.

computeIfAbsent 检查键是否存在并锁定 map 的某些部分。然后它调用仿函数并将结果放入映射(如果返回值不为空)。只有在那之后这部分 map 才被解锁。

另一方面,test3总是调用c.call(),计算结束后调用putIfAbsent。

关于java - 为什么 ConcurrentHashMap::putIfAbsent 比 ConcurrentHashMap::computeIfAbsent 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40081456/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com