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