2012-07-10 83 views
0

我不理解下面的代碼片斷如何能夠線程安全。使用線程安全集合的多個線程

class MapUser { 
    Map<String,Integer> map = new ConcurrentHashMap<String,Integer> 

    public void addToMap(String str, Integer val){ 
     if(checkMagicString(str)){ 
      map.put(str,val); 
     } 
    } 

    private boolean checkMagicString(String str){ 
     //some logic to check Magic 
     //this logic involved operation on the String parameter str i.e. subString,toCharArray etc 
    } 
} 

注意方法addToMap被多個線程同時調用。我想確保線程的安全性。通過使用ConcurrentHashMap,我可以確保線程安全地將值添加到它。

但是我不明白如何方法checkMagicString(String str)可以保持線程安全?唯一的辦法是讓它同步嗎?或者應該使調用方法addToMap同步? 請注意,我沒有訪問checkMagicString方法內的地圖。

+2

我假設你正在訪問'checkMagicString'內的'map'?如果沒有,那麼你很好。如果你是那麼請編輯你的帖子以表明這一點。 – Gray 2012-07-10 16:58:50

回答

2

即使你做checkMagicString原子,它不會使該序列

if(checkMagicString(str)){ 
    map.put(str,val); 
} 

原子,因爲一個線程可以在if檢查和map.put調用之間被中斷,因此你可能最終有兩個線程插入相同的字符串。您需要鎖定整個序列以確保安全。

編輯:如果上述是可接受的行爲(即,兩個線程插入相同的密鑰和覆蓋值)和checkMagicString不會在共享狀態操作然後代碼是細因爲它是。

+0

這真的取決於checkMagicString在做什麼。只要它不訪問映射,這2個操作就不必是原子來維護線程安全。 – assylias 2012-07-10 17:02:19

+0

@assylias:這兩個操作不,但順序應該是,因爲我認爲他不想讓兩個線程放置相同的字符串。 – Tudor 2012-07-10 17:03:00

+0

你的意思是使用synchronized的addToMap方法嗎?如果這是必需的,那麼多線程的好處在哪? – Eager 2012-07-10 17:03:49

0

如果你想要的是一個原子操作的情況下做到這樣是爲了確保checkMagicStr原子,並且還使用了地圖上的原子操作的最好的事情:

boolean done = false; 
while(!done) { 
    Integer oldVal = map.get(str); 
    if (checkMagicStr(str) { 
    if (oldVal != null) { 
     done = value == map.replace(str, val, oldVal); // otherwise try again... 
    } else { 
     done = null == map.putIfAbsent(str, val); // otherwise try again... 
    } 
    } else { 
    done = true; // there's nothing to do... 
    } 
} 

你可能想在while循環中有一個限制,並且如果它被觸發就會拋出異常,因爲這可能會在高度併發的系統上永遠運行。從你的問題中不清楚爲什麼這些都是必要的,儘管如此,B/C你所擁有的將是「線程安全的」,但也許這會有所幫助。