我正在做一些事情,我有一個Collections.synchronizedMap定義。Java地圖同步
在一個線程A中,它只會得到該值,並放置一個更新值,所以它不是問題。
在另一個線程B中,它將遍歷條目,然後根據條目的值進行比較,如果匹配某個條件,則會從地圖中刪除該條目。
我的理解是,一個同步的地圖將阻止訪問。
但是有可能線程B獲得一個條目,然後線程A更新該值,然後線程B刪除該值,因爲它匹配某些條件,但它不應該因爲值而將線程A更新爲。什麼是最好的實施來解決這個問題?
我正在做一些事情,我有一個Collections.synchronizedMap定義。Java地圖同步
在一個線程A中,它只會得到該值,並放置一個更新值,所以它不是問題。
在另一個線程B中,它將遍歷條目,然後根據條目的值進行比較,如果匹配某個條件,則會從地圖中刪除該條目。
我的理解是,一個同步的地圖將阻止訪問。
但是有可能線程B獲得一個條目,然後線程A更新該值,然後線程B刪除該值,因爲它匹配某些條件,但它不應該因爲值而將線程A更新爲。什麼是最好的實施來解決這個問題?
聽起來你只需要同步「獲取,檢查和刪除」部分。例如:
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);
}
}
}
你更新線程可能需要做同樣的事情 - 這是從你的描述不清楚它是否需要「看」的缺失。
您需要同步您正在使用該地圖的代碼塊。
到這裏看看: Java synchronized block vs. Collections.synchronizedMap
這聽起來像你正試圖實現一個高速緩存。那裏有很多好的併發緩存實現。我相信guava有一個相當不錯的實現。
這完全可以做到不使用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中可能會有多次重複調用,具體取決於比較所需的時間以及值的更改頻率。但是在任何情況下,這都將是線程安全的,並且比任何同步實現都快。
首先是解決方案。我認爲最好的解決方案是標準的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>
您可以鎖定批評部分,並避免問題 –