插入并发哈希映射

inserting in a concurrent hash map

以下代码没有按预期运行。当我在 Does class 中调用 put 方法时,并发哈希映射中的值与映射的不同实例相关联。所以我想做的是多个线程访问同一个映射并为同一个键插入一个值。但是,如果我将 synchronized 关键字添加到 put 方法,它就可以工作。我错过了什么?

class Does implements Runnable {
    C2 c2;

    Does(C2 c2) {
        this.c2 = c2;
    }

    public void run() {
        c2.put("Hello");
    }

}

public class C2 {
    public ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<String, List<String>>();

    public static void main(String args[]) {
        C2 c2 = new C2();
        new Thread(new Does(c2)).start();
        new Thread(new Does(c2)).start();
        new Thread(new Does(c2)).start();
        new Thread(new Does(c2)).start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        List<String> lu = c2.map.get("Hello");

        System.out.println(lu);
    }

    /**
     * @param string
     */
    public void put(String string) {
        if (map.containsKey(string)) {
            List<String> li = map.get(string);
            li.add("adding something");
        } else {
            List<String> li = new ArrayList<String>();
            li.add("adding something");
            map.put(string, li);
        }
    }

}

感谢帮助。

这段代码不是线程安全的

public void put(String string) {
    if (map.containsKey(string)) {
        // anything can happen in another thread here
        List<String> li = map.get(string);
        // anything can happen in another thread here
        li.add("adding something");
    } else {
        // anything can happen in another thread here
        List<String> li = new ArrayList<String>();
        li.add("adding something");
        // anything can happen in another thread here
        map.put(string, li);
    }

在Java8中你可以使用computeIfAbsent。

public void put(String string) {
    // all most thread safe.
    map.computeIfAbsent(string, k -> new ArrayList<>())
       .add("add something");
}

请注意,这仍然不是线程安全的,因为 ArrayList 不是线程安全的,所以您需要的是

public void put(String string) {
    List<String> list = map.computeIfAbsent(string, k -> new ArrayList<>());
    synchronized(list) {
       list.add("add something");
    }
}