首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么ConcurrentHashMap::putIfAbsent比ConcurrentHashMap::computeIfAbsent更快?

为什么ConcurrentHashMap::putIfAbsent比ConcurrentHashMap::computeIfAbsent更快?
EN

Stack Overflow用户
提问于 2016-10-17 08:13:48
回答 1查看 1.9K关注 0票数 4

玩ConcurrentHashMap时,我发现computeIfAbsent比putIfAbsent慢两倍。这里是一个简单的测试:

代码语言:javascript
运行
复制
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())的执行时间是10068 my,对于testCase2 (它执行相同的东西,但没有将它包装到computeIfAbsent()中),执行时间是5009 my(当然它有一些变化,但主要趋势是这样的)。最有趣的是testCase3 --它与testCase1差不多(除了使用putIfAbsent()而不是computeIfAbsent()),但它的执行速度要快两倍( testCase3为5010‘s,testCase1为10068’s)。

查看源代码,对于computeIfAbsent()和putVal() (它在putIfAbsent()中使用)来说几乎是一样的。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-17 12:13:08

您会看到文档化的特性:

在计算过程中,其他线程对此映射的一些尝试更新操作可能会被阻止,因此计算应该是简短和简单的,并且不能试图更新此映射的任何其他映射。

computeIfAbsent检查密钥是否存在,并锁定映射的某些部分。然后调用函子并将结果放入map (如果返回的值不是null)。只有在那之后,地图的这一部分才被打开。

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40081456

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档