在这种情况下如何处理并发?
How to handle concurrency in this case?
我有一个 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;
}
但是如您所见,这可能不是处理并发的理想选择,因为只有同一键下的值可能会干扰每个 other.Different 键不会相互干扰,因此没有必要同步所有操作.我只想在key相同的时候同步
我可以做一些可以提高并发性能的事情吗?
(我知道 ConcurrentHashMap 和 synchronize 在这里有点多余,但让我们关注一下是否只能在 key 相同时同步)
首先,key是从哪里来的?
其次,如果两个线程的键永远不会相同 运行 在任何时候都起作用,则您不需要同步该函数的任何部分。
但是,如果两个线程可以同时拥有相同的密钥,那么您只需要:
synchronized(count) {
count.put(key, order + 1);
}
这样做的原因是只需要同步对象变量的线程变更。但事实上你使用的是 ConcurrentHashMap
should 消除这个问题(仔细检查我),因此不需要同步.
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;
}
有关详细信息,请参阅 JavaputIfAbsent() and replace() 的文档。
As Tagir Valeev points out , you can use merge() 相反,如果你在 Java 8,这会将上面的代码缩短为:
private Integer somefunction() {
return count.merge(key, 1, Integer::sum) - 1;
}
另一种选择是将值设置为 AtomicInteger instead. See 以了解如何做到这一点。
我是这样操作的,
private Integer somefunction(){
Integer order = count.compute(key, (String k, Integer v) -> {
if (v == null)
return 1;
else {
return v + 1;
}
});
return order-1;
}
这避免一直尝试使用 replace(key,oldValue,newValue)
这对并发性会更好吗?
问题是很多环境还不支持jdk8
我认为这可能更好更简单 -
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();
}
如果你能用Java-8:
就很简单了
return count.merge(key, 1, Integer::sum)-1;
不需要额外的同步。 merge
方法保证以原子方式执行。
我有一个 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;
}
但是如您所见,这可能不是处理并发的理想选择,因为只有同一键下的值可能会干扰每个 other.Different 键不会相互干扰,因此没有必要同步所有操作.我只想在key相同的时候同步
我可以做一些可以提高并发性能的事情吗? (我知道 ConcurrentHashMap 和 synchronize 在这里有点多余,但让我们关注一下是否只能在 key 相同时同步)
首先,key是从哪里来的?
其次,如果两个线程的键永远不会相同 运行 在任何时候都起作用,则您不需要同步该函数的任何部分。
但是,如果两个线程可以同时拥有相同的密钥,那么您只需要:
synchronized(count) {
count.put(key, order + 1);
}
这样做的原因是只需要同步对象变量的线程变更。但事实上你使用的是 ConcurrentHashMap
should 消除这个问题(仔细检查我),因此不需要同步.
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;
}
有关详细信息,请参阅 JavaputIfAbsent() and replace() 的文档。
As Tagir Valeev points out
private Integer somefunction() {
return count.merge(key, 1, Integer::sum) - 1;
}
另一种选择是将值设置为 AtomicInteger instead. See
我是这样操作的,
private Integer somefunction(){
Integer order = count.compute(key, (String k, Integer v) -> {
if (v == null)
return 1;
else {
return v + 1;
}
});
return order-1;
}
这避免一直尝试使用 replace(key,oldValue,newValue) 这对并发性会更好吗?
问题是很多环境还不支持jdk8
我认为这可能更好更简单 -
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();
}
如果你能用Java-8:
就很简单了return count.merge(key, 1, Integer::sum)-1;
不需要额外的同步。 merge
方法保证以原子方式执行。