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

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 方法保证以原子方式执行。