2014-01-28 66 views
0

我正在做一些事情,我有一個Collections.synchronizedMap定義。Java地圖同步

在一個線程A中,它只會得到該值,並放置一個更新值,所以它不是問題。

在另一個線程B中,它將遍歷條目,然後根據條目的值進行比較,如果匹配某個條件,則會從地圖中刪除該條目。

我的理解是,一個同步的地圖將阻止訪問。

但是有可能線程B獲得一個條目,然後線程A更新該值,然後線程B刪除該值,因爲它匹配某些條件,但它不應該因爲值而將線程A更新爲。什麼是最好的實施來解決這個問題?

+0

您可以鎖定批評部分,並避免問題 –

回答

2

聽起來你只需要同步「獲取,檢查和刪除」部分。例如:

Iterable<String> keys; 
synchronized (map) { 
    keys = new ArrayList<>(map.keySet()); 
} 
for (String key : keys) { 
    synchronized (map) { 
     Integer value = map.get(key); 
     // The other thread won't be able to update the value at this point 
     if (value != null && value < 0) { 
      map.remove(key); 
     } 
    } 
} 

你更新線程可能需要做同樣的事情 - 這是從你的描述不清楚它是否需要「看」的缺失。

0

這聽起來像你正試圖實現一個高速緩存。那裏有很多好的併發緩存實現。我相信guava有一個相當不錯的實現。

1

這完全可以做到不使用ConcurrentHashMap這樣阻塞:

final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); // creation 
map.put("aKey", "aValue"); // example content 

// Thread A: 
map.replace("aKey", "aNewValue"); // atomic replace call 

// Thread B: 
for (String key : map.keySet()) { 
    do { 
    processed = true; 
    final String value = map.get(key); 
    if ((value != null) && shouldRemove(value)) { // some comparison or check 
     if (map.remove("aKey", value) == false) { // is value still the same? 
     processed = false; // value has been changed in between, try again 
     } 
    } 
    } while (processed == false); 
} 

這是線程安全的,因爲線程B僅刪除值(原子),如果它沒有被改變之間英寸如果兩者之間發生變化,線程B將再次嘗試並使用新值進行比較。這與其他原子類中使用的compareAndSet的概念類似。

如果線程A很少發生變化,線程B將執行與未同步映射幾乎相同的速度。如果線程A做了很多更改,則線程B中可能會有多次重複調用,具體取決於比較所需的時間以及值的更改頻率。但是在任何情況下,這都將是線程安全的,並且比任何同步實現都快。

0

首先是解決方案。我認爲最好的解決方案是標準的ConcurrentHashMap。它有CAS操作刪除如下:

boolean remove(Object key, Object value) 
Removes the entry for a key only if currently mapped to a given value. 

希望它有幫助。

現在的第二件事是關於「我的理解是,一個同步的地圖將阻止訪問。」我不認爲是完全理解,因爲看到下面的同步地圖javadoc細節:

* It is imperative that the user manually synchronize on the returned 
* map when iterating over any of its collection views: 
* <pre> 
* Map m = Collections.synchronizedMap(new HashMap()); 
*  ... 
* Set s = m.keySet(); // Needn't be in synchronized block 
*  ... 
* synchronized (m) { // Synchronizing on m, not s! 
*  Iterator i = s.iterator(); // Must be in synchronized block 
*  while (i.hasNext()) 
*   foo(i.next()); 
* } 
* </pre>