簡體   English   中英

為什么ConcurrentHashMap不將地圖的大小存儲在AtomicInteger中?

[英]Why does ConcurrentHashMap not store the size of the map in a AtomicInteger?

ConcurrentHashMapsize()方法的JavaDoc中,它指出:

“記住,骨料狀態方法,包括結果sizeisEmpty ,和containsValue通常僅在一個地圖沒有發生在其他線程並發更新有用的。”

我知道,在大多數並發應用程序中,地圖本質上是移動目標,因此,通常需要由size()方法返回的值被保證是正確的。 但就我而言,我實際上確實需要它正確(不是陳舊的值)。

似乎我真的不想為每個size()調用鎖定整個表,我的問題是為什么ConcurrentHashMap不僅將表的大小存儲在AtomicInteger字段中,該字段作為put()一部分進行更新或remove()操作? 如果這樣做,那么對size字段的寫入將始終是原子的(並且由於AtomicInteger將其值存儲在volatile字段中),那么從size字段進行的任何讀取都將返回該字段的最新版本。 。

還是我在這里想念什么?

是的,您缺少一些東西。 想象一下有10個線程執行更新,第11個線程定期確定地圖的大小。

第11個線程讀取的數字完全取決於其他10個線程的執行時間。 在這里使用原子整數將無濟於事。

ruediste所述 ,如果正在進行並發更新,則大小信息毫無意義。 如果進行多次更新,則可以獲取舊值,新值或任意中間值。

這與值是否存儲在原子整數中無關。 但是,關於ConcurrentHashMap的全部要點是允許並發更新。

“並發”表示沒有時間關系,也沒有動作順序。 當一個線程嘗試插入一個值而另一個線程嘗試刪除一個值時, 只有當他們訪問相同的鍵時才存在時間關系。 在這種情況下,刪除線程可以使用結果來判斷插入是否發生在刪除之前。 在所有其他情況下,線程獨立運行。

同時查詢尺寸時,您可能會得到舊尺寸,舊尺寸加一或舊尺寸減一(以防初始狀態不為空)。 如果您得到的值與以前的大小不同,則可以用它來推斷是先進行插入還是先進行刪除,然后得出錯誤的結論。 同時使用containsKey的另一個線程來檢測是否存在任何一個密鑰可能會感知這些操作的順序不同。 這就是“無序”或“無時間關系”的含義。

保持原子整數大小值不會有任何改變。 仍然有一個地方線程修改了地圖的內容,但還沒有修改大小字段。 此時,可能有任意數量的線程。 但是,強制所有線程更新單個原子整數將大大減少並發性。 盡管一個原子整數比synchronized塊快,但它仍然是一種同步動作,遭受高競爭。 因此,它將降低性能而不會解決任何問題。

事實1:更新單個size字段可能會成為並發瓶頸,無論是將其實現為volatile intAtomicInteger還是其他方式。

事實2:在ConcurrentHashMap的絕大多數用例中, size()方法對應用程序無用,因為它只告訴您特定時刻的大小。 (如果那樣的話。javadoc實際上並沒有指定面對並發更新時將返回什么size() 。)

如果我們假設不太可能調用size() ,那么對更新操作引入潛在的並發瓶頸,以防萬一它被調用對我來說似乎是一個壞主意。 我猜想作者(Doug Lea)有類似的想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM