我有一个HashMap
ConcurrentHashMap<String, Integer> count =new ConcurrentHashMap<String, Integer>();
我将这样使用:
private Integer somefunction(){
Integer order;
synchronized (this) {
if (count.containsKey(key)) {
order = count.get(key);
count.put(key, order + 1);
} else {
order = 0;
count.put(key, order + 1);
}
}
return order;
}
但正如您所看到的,这对于处理并发性可能并不理想,因为只有相同密钥下的值可能会相互干扰。不同的密钥不会相互干扰,因此无需同步所有操作。我想只在密钥相同时进行同步。
我能做一些可以在并发上获得更好性能的东西吗? (我知道ConcurrentHashMap和同步在这里是多余的,但如果我们只能在密钥相同的情况下进行同步,那就让我们关注一下)
答案 0 :(得分:4)
ConcurrentHashMap
的重点是促进并发操作。以下是无需显式同步即可进行原子更新的方法:
private Integer somefunction() {
Integer oldOrder;
// Insert key if it isn't already present.
oldOrder = count.putIfAbsent(key, 1);
if (oldOrder == null) {
return 0;
}
// If we get here, oldOrder holds the previous value.
// Atomically update it.
while (!count.replace(key, oldOrder, oldOrder + 1)) {
oldOrder = count.get(key);
}
return oldOrder;
}
有关详细信息,请参阅putIfAbsent()和replace()的Javadoc。
当Tagir Valeev指出in his answer时,如果您使用的是Java 8,则可以使用merge(),这会将上面的代码缩短为:
private Integer somefunction() {
return count.merge(key, 1, Integer::sum) - 1;
}
另一个选择是让值为AtomicInteger。有关如何操作,请参阅hemant1900's answer。
答案 1 :(得分:1)
我认为这可能会更好更简单 -
private final ConcurrentHashMap<String, AtomicInteger> count = new ConcurrentHashMap<String, AtomicInteger>();
private Integer someFunction(String key){
AtomicInteger order = count.get(key);
if (order == null) {
final AtomicInteger value = new AtomicInteger(0);
order = count.putIfAbsent(key, value);
if (order == null) {
order = value;
}
}
return order.getAndIncrement();
}
答案 2 :(得分:1)
如果你可以使用Java-8,这很容易:
return count.merge(key, 1, Integer::sum)-1;
无需额外同步。保证merge
方法以原子方式执行。
答案 3 :(得分:0)
首先,钥匙来自哪里?
其次,如果在任何时候运行该函数的两个线程的密钥永远不会相同,则不需要同步函数的任何部分。
但是,如果两个线程同时拥有相同的密钥,那么您只需要:
synchronized(count) {
count.put(key, order + 1);
}
原因是只需要同步对象变量的线程变异。但是您使用ConcurrentHashMap
的事实 可以消除此问题(请仔细检查我),因此无需同步。
答案 4 :(得分:-1)
我是这样做的,
require_once("http://www.yourserver.com/function.php");
这样可以避免尝试使用替换(key,oldValue,newValue) 并发会更好吗?
问题是很多环境还不支持jdk8。