3

我有一個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

你能解釋一下你想達到什麼嗎? –

+0

不同的鍵不會互相干擾,因此不需要同步所有操作。我只想在密鑰相同的情況下進行同步。 –

+0

它看起來像你想要的算法是「如果鍵沒有從地圖上,插入一個訂單值爲1,並返回0.如果該項目存在於地圖中,遞增其順序值,並返回之前的值增量。」它是否正確? – mattinbits

回答

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; 
} 

見的Javadoc putIfAbsent()replace()瞭解詳情。

由於Tagir Valeev指出in his answer,你可以使用merge(),而是如果你對Java的8,這將縮短上面的代碼:

private Integer somefunction() { 
    return count.merge(key, 1, Integer::sum) - 1; 
} 

另一種選擇是讓值是AtomicInteger代替。請參閱hemant1900's answer瞭解如何操作。

+0

返回0;返回oldOrder; –

+0

@董育佳:完成,感謝您的糾正。 – markusk

0

首先,key甚至來自哪裏?其次,如果在任何時候運行該函數的兩個線程的鍵永遠不會相同,則不需要同步該函數的任何部分。

但是,如果兩個線程可以在同一時間同一個密鑰,那麼你只需要:

synchronized(count) { 
    count.put(key, order + 1); 
} 

這樣做的原因是,一個對象變量的唯一線程突變,將需要同步。但事實上,您正在使用ConcurrentHashMap應該消除此問題(請仔細檢查我),因此不需要同步。

-1

這是我如何做到這一點,

private Integer somefunction(){ 
    Integer order = count.compute(key, (String k, Integer v) -> { 
     if (v == null) 
     return 1; 
     else { 
     return v + 1; 
     } 
    }); 
    return order-1; 
} 

這避免不停地嘗試使用取代(鍵,屬性oldValue,NEWVALUE) 這會不會是併發更好?

問題是很多環境還不支持jdk8。

+0

如果你要依賴於Java 8,@ tagir-valeev的使用'merge()'的建議似乎比'compute()'更好。 – markusk

+0

@markusk剛剛發現'merge()'更好 –

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(); 
} 
1

這很容易,如果你可以使用Java-8:

return count.merge(key, 1, Integer::sum)-1; 

沒有額外的同步是必要的。保證以原子方式執行merge方法。