2014-02-26 50 views
0

[問題]:它是線程安全的使用ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>>與否。一個內部另一個併發收集:是線程安全

[可選回答]:還有什麼關於另一個並行的地圖類型?那麼併發集合呢?

附:我只問java.util.concurrent包。

具體用法語境:

//we have 
ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>> map = new ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>>(); 
//each string can be executed separately and concurently 
ConcurrentHashMap<Object, Object> subMap = new ConcurrentHashMap<Object, Object>() 
map.put(key, subMap); 
map.remove(key); 
map.get(key); 
map.get(key).put(key, ref); 
map.get(key).remove(key); 

也許我的解決方案奠定了周圍番石榴HashBasedTable?

+0

這是爲什麼? ConcurrentHashMap畢竟是線程安全的。 – Antoniossss

+0

@Keppil我希望有人描述的情況不是 –

+0

這段代碼似乎沒有編譯。沒有map.put(object)方法。 –

回答

1

併發集合對於讀取是線程安全的;但是如果存在競爭併發更新或在另一個線程遍歷它時修改集合,則必須期望ConcurrentModificationException

+0

請參閱injecteer的回答。他說,他們是線程安全的寫入。誰是對的?更多的解釋請 –

3

如果沒有您計劃使用集合的特定上下文,則無法定義線程安全性。

你命名的併發集合是線程安全的他們在這個意義上,他們內部的不變量不會被併發訪問被打破自己的;不過這只是線程安全清單上的一個重點。

如果您在結構上執行的任何操作都不止一個操作,它必須是整個原子操作,那麼僅通過使用這些類就不會獲得線程安全。你將不得不求助於經典的鎖定,或者一些相當複雜的,通常沒有動機的無鎖更新方案。

使用您問題中的示例,請考慮以下事項。

線程1執行

map.get(mapKey).put(key, value); 

同時,線程2執行

map.remove(mapKey); 

是什麼結果?線程1可能會將某些內容放置到已刪除的地圖上,或者甚至可能從get獲得null結果。在大多數情況下,正確性需要更多的協調。

+0

似乎是我必須理解的東西,但我不知道。請你能提供解釋的簡單例子嗎? –

+0

看看我的問題的更新版本。我已經添加了上下文定義。 –

+0

什麼是'asMap'?這不是'ConcurrentHashMap'的一種方法。 –

1

這是什麼ConcurrentHashMap的Javadoc說:

不過,儘管所有操作都是線程安全的,檢索操作並不意味着鎖定,並沒有在鎖定整個表的任何支持防止所有訪問的方式

因此,它們在修改它時是線程安全的。

UPDATE

相同的javadoc http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html說:

檢索操作(包括get)通常不會阻塞,因此,(包括投資和刪除)可能與更新操作重疊。檢索反映了最近完成的更新操作的結果。對於putAll和clear等集合操作,併發檢索可能反映插入或刪除僅某些條目。類似地,Iterator和Enumerations在迭代器/枚舉創建時或之後返回反映哈希表狀態的元素。 他們不會拋出ConcurrentModificationException。但是,迭代器被設計爲一次只能由一個線程使用。

+0

請不要線程安全的情況下。請。那麼'HashTable'呢? –

+0

我會說哈希表以及幾乎所有的java基本集合類型都是線程安全的在閱讀的情況下。只有當你同時寫和/或讀時,你可能會遇到像ConcurrentModificationException這樣的問題。 – injecteer

+0

是否有任何Java語言地圖在同時讀寫的環境中是安全的(就像我在上下文中定義的部分一樣)? –

1

通常,作爲java.util.concurrent一部分的類在額外的編碼複雜性的(潛在的)代價下提供額外的性能。

我看到的嵌套ConcurrentMap實例的問題是管理使用給定鍵的值填充外部映射。如果所有鍵都是預先知道的,並且在某種初始化階段將值放置在映射中,則不存在問題(但您也可能不需要使外部映射爲併發映射)。如果您需要能夠隨時將新地圖插入外部地圖,則工作會變得更加複雜。當創建一個插入外部映射的新映射時,您需要使用putIfAbsentmethod [1]並注意返回的值以確定將數據添加到哪個實例。

[1] - http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K,%20V)

+0

你想說如果我使用'puIfAbsent'方法將我的場景線程安全嗎? –

+0

沒有足夠的數據可以肯定地說,這將使整個場景線程安全。使用該方法填充外部地圖幾乎肯定會成爲所需工作的一部分。必須知道的是什麼工作必須被視爲原子。 –

+1

刪除的使用也提出了挑戰。在移除過程中,或多或少不可能判斷一個競爭線程是否真正在您要移除的關鍵點處操作該地圖。一旦設置了一個值,將空的地圖保留在值中會簡單得多。 –

相關問題