Java ConcurrentHashMap上的同步
在我的应用程序中,我使用的是ConcurrentHashMap,我需要原子地执行这种类型的“如果不存在自定义put”方法Java ConcurrentHashMap上的同步,java,multithreading,concurrency,synchronized,java.util.concurrent,Java,Multithreading,Concurrency,Synchronized,Java.util.concurrent,在我的应用程序中,我使用的是ConcurrentHashMap,我需要原子地执行这种类型的“如果不存在自定义put”方法 public boolean putIfSameMappingNotExistingAlready(String key, String newValue) { String value; synchronized (concurrentHashMap) { if (value = concurrentHashMap.putIfAbsent(key,
public boolean putIfSameMappingNotExistingAlready(String key, String newValue) {
String value;
synchronized (concurrentHashMap) {
if (value = concurrentHashMap.putIfAbsent(key, newValue)) == null) {
// There was no mapping for the key
return true;
} else { if (value.equals(newValue)) {
// The mapping <key, newValue> already exists in the map
return false;
} else {
concurrentHashMap.put(key, newValue);
return true;
}
}
}
}
public boolean putIfSameMappingNotExistingAlready(字符串键,字符串newValue){
字符串值;
已同步(concurrentHashMap){
if(value=concurrentHashMap.putIfAbsent(key,newValue))==null){
//没有密钥的映射
返回true;
}else{if(value.equals(newValue)){
//映射已存在于映射中
返回false;
}否则{
concurrentHashMap.put(键,newValue);
返回true;
}
}
}
}
我(在并发包文档中)读到
并发集合是线程安全的,但不受单个排除锁的控制
因此,您无法在ConcurrentHashMap上获得独占锁
我的问题是:
非常感谢 以下代码使用比较和设置循环(如SlakS所建议的)来实现线程安全(注意无限循环):
以下代码使用比较和设置循环(如SlakS所建议的)来实现线程安全(注意无限循环):
通过像这样对整个集合进行同步,您实际上是在用自己的钝器方法替换并发集合中的细粒度同步
如果您没有在其他地方使用并发保护,那么您可以使用标准的
HashMap
,并将其包装到您自己的同步中。使用synchronizedMap
可能会起作用,但不会涵盖多步骤操作,例如上面的放置、检查、放置操作。通过对整个集合进行同步,就像您基本上用自己的钝器方法替换并发集合中的细粒度同步一样
如果您没有在其他地方使用并发保护,那么您可以使用标准的
HashMap
,并将其包装到您自己的同步中。使用synchronizedMap
可能会起作用,但不会涵盖多步操作,例如上面的放置、检查、放置位置。它真的是“concurrentHashMap.putIfAbsent(msg,msg)”吗?@isnot2bad不,我更正了它,谢谢您使用比较和设置循环而不是锁@ovdsrn您在编辑中建议的代码将不起作用,因为如果此键已经有映射,则putIfAbsent不会执行任何操作。@isnot2bad您完全正确,愚蠢的我,我将删除编辑,因为它毫无意义。它真的是“concurrentHashMap.putIfAbsent(msg,msg)”吗?@isnot2bad否,我更正了它,谢谢你使用比较和设置循环而不是锁@ovdsrn您在“编辑”中建议的代码将不起作用,因为如果该键已存在映射,则putIfAbsent不会执行任何操作。@Isnot2如果您完全正确,愚蠢的我,我将删除该编辑,因为它毫无意义。您的建议不会让您知道映射是否已存在于映射中。您将只能确定是否存在该键的映射。注意,如果Java 7,nullSafeEquals()
可以替换为Objects.equals()
@fge Fine。我不确定它是Java 7还是Java 8。+1我唯一要说的是concurrentHashMap。putIfAbsent
每次都会获得一个锁,如果有许多replace
或对象,这可能会降低吞吐量。equals
调用正在进行。我会先获取oldValue
,然后在执行PutiAbsent测试(重新分配oldValue时)时,如果它为null,我会使用putiAbsent
的返回值完全删除get
。(如果条目已经存在,putIfAbsent
应该像get
一样处理吞吐量问题)。现在代码更简单了。您的建议不会让您知道映射是否已经在映射中。您将只能确定是否存在该键的映射。注意,如果Java 7,nullSafeEquals()
可以替换为Objects.equals()
@fge Fine。我不确定它是Java 7还是Java 8。+1我唯一要说的是concurrentHashMap。putIfAbsent
每次都会获得一个锁,如果有许多replace
或对象,这可能会降低吞吐量。equals
调用正在进行。我会先获取oldValue
,然后在执行PutiAbsent测试(重新分配oldValue时)时,如果它为null,我会使用putiAbsent
的返回值完全删除get
。(如果条目已经存在,putIfAbsent
应该像get
一样处理吞吐量问题)。现在代码更简单了。
/**
* Updates or adds the mapping for the given key.
* Returns true, if the operation was successful and false,
* if key is already mapped to newValue.
*/
public boolean updateOrAddMapping(String key, String newValue) {
while (true) {
// try to insert if absent
String oldValue = concurrentHashMap.putIfAbsent(key, newValue);
if (oldValue == null) return true;
// test, if the values are equal
if (oldValue.equals(newValue)) return false;
// not equal, so we have to replace the mapping.
// try to replace oldValue by newValue
if (concurrentHashMap.replace(key, oldValue, newValue)) return true;
// someone changed the mapping in the meantime!
// loop and try again from start.
}
}