Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 插入并发哈希映射_Java_Concurrenthashmap - Fatal编程技术网

Java 插入并发哈希映射

Java 插入并发哈希映射,java,concurrenthashmap,Java,Concurrenthashmap,下面的代码无法按预期工作。当我在Does类中调用put方法时,并发哈希映射中的值与映射的不同实例相关联。所以我要做的是多个线程访问同一个映射,并为同一个键插入一个值。但是,如果我向put方法添加一个synchronized关键字,它就会工作。我错过了什么 class Does implements Runnable { C2 c2; Does(C2 c2) { this.c2 = c2; } public void run() {

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

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);
        }
    }

}
类不实现可运行{
C2;
DOS(C2){
这1.c2=c2;
}
公开募捐{
c2.打招呼(“你好”);
}
}
公共级C2{
public ConcurrentHashMap=新ConcurrentHashMap();
公共静态void main(字符串参数[]){
C2=新的C2();
新线程(新执行(c2)).start();
新线程(新执行(c2)).start();
新线程(新执行(c2)).start();
新线程(新执行(c2)).start();
试一试{
睡眠(3000);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
List lu=c2.map.get(“Hello”);
系统输出打印项数(lu);
}
/**
*@param字符串
*/
公共作废put(字符串){
if(map.containsKey(字符串)){
List li=map.get(字符串);
添加(“添加某物”);
}否则{
List li=new ArrayList();
添加(“添加某物”);
map.put(字符串,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);
    }
public void put(字符串){
if(map.containsKey(字符串)){
//任何事情都可能发生在另一个线程中
List li=map.get(字符串);
//任何事情都可能发生在另一个线程中
添加(“添加某物”);
}否则{
//任何事情都可能发生在另一个线程中
List li=new ArrayList();
添加(“添加某物”);
//任何事情都可能发生在另一个线程中
map.put(字符串,li);
}
在Java8中,可以使用ComputeFabSent

public void put(String string) {
    // all most thread safe.
    map.computeIfAbsent(string, k -> new ArrayList<>())
       .add("add something");
}
public void put(字符串){
//所有这些都是线程最安全的。
computeIfAbsent(string,k->new ArrayList())
.添加(“添加某物”);
}
注意这仍然不是线程安全的,因为ArrayList不是线程安全的,所以您需要的是

public void put(String string) {
    List<String> list = map.computeIfAbsent(string, k -> new ArrayList<>());
    synchronized(list) {
       list.add("add something");
    }
}
public void put(字符串){
List List=map.computeIfAbsent(string,k->new ArrayList());
已同步(列表){
添加(“添加某物”);
}
}

什么不按预期工作?所有4个线程都可能看到映射不包含密钥,然后尝试添加它。是的,但是对于并发哈希映射,put方法被认为是线程安全的。所以我猜这不应该是一个问题?有趣的是,并发哈希映射put方法不是线程安全的吗?Javadoc说至少,并发哈希映射的所有操作都是线程safe@Krish你不明白什么是“线程安全”意思是。每个单独的操作都是线程安全的,但您将它们组合在一起会失去线程安全。@LouisWasserman公平地说,这是StringBuffer的设计者忽略了IMHO的一点。SimpleDataFormat不是线程安全的,可能是因为他们使用了StringBuffer,并期望它能为他们实现线程安全。@Krish,正如我所说的那样。@在我的回答中,任何事情都可能发生在某些点上。这会破坏线程安全。线程安全不是魔法,它的使用方式也很重要。注意:你可以根据你如何使用它来获取非线程安全的代码。@PeterLawrey感谢你的回答。我提供了帮助。