在这种情况下如何处理并发?

时间:2015-08-20 06:40:47

标签: java multithreading concurrency hashmap java.util.concurrent

我有一个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和同步在这里是多余的,但如果我们只能在密钥相同的情况下进行同步,那就让我们关注一下)

5 个答案:

答案 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。