[英]How can I perform a thread-safe get then remove with ConcurrentHashMap?
在一次采訪中,我被要求檢查以下代碼是否按預期工作。
ConcurrentHashMap<Integer, Integer> chm = new ConcurrentHashMap<>();
if (chm.get(key) != null) {
chm.get(key).doSomething();
chm.remove(key);
}
根據JavaDocs, get
上次完成的更新操作的返回值。 因此,如果線程1已經調用了chm.remove(key)
並且如果線程2進入if語句並且即將調用get
方法,那么我們可能會得到一個異常。 它是否正確?
我怎樣才能使這個線程安全?
如果已刪除,則Map.remove(key)
返回值。 在許多情況下,這是一個非常好的技巧,包括你的:
Object value = chm.remove(key)
if(value != null)
{
value.doSomething();
}
你不能安全地使用get然后刪除,因為如果兩個線程同時調用你的方法,那么在刪除密鑰之前,他們總是存在兩次或多次調用doSomething
的風險。
如果先將其刪除,則無法進行此操作。 上面的代碼是Threadsafe,也更簡單。
你是對的。 如果這個Map
可以被多個線程修改,那么對chm.get(key)
的第一次調用可能會返回一個非null值,而第二次調用將返回null
(由於從Map
完成的Map
刪除了鍵)另一個線程),因此chm.get(key).doSomething()
將拋出一個NullPointerException
。
您可以使用局部變量來存儲chm.get(key)
的結果,從而使此代碼線程安全:
ConcurrentHashMap<Integer, Integer> chm = new ConcurrentHashMap<Integer, Integer>();
Integer value = chm.get(key);
if(value != null) {
value.doSomething(); // P.S. Integer class doesn't have a doSomething() method
// but I guess this is just an example of calling some arbitrary
// instance method
chm.remove(key);
}
順便說一句,即使Map
不是ConcurentHashMap
並且只有一個線程可以訪問它,我仍然使用局部變量,因為它比調用get()
方法兩次更有效。
編輯:
如下面所述,此修復程序不會阻止doSomething()
被不同的線程多次調用相同的鍵/值。 這是否是所期望的行為並不清楚。
如果您希望防止多個線程為同一個鍵/值調用doSomething()
chm.remove(key)
,您可以使用chm.remove(key)
來刪除鍵並在同一步驟獲取值。
然而,這會冒一些鍵/值根本不會執行doSomething()
的風險,因為如果第一次調用doSomething()
導致異常,則不會再由另一個線程調用doSomething()
,因為鍵/值對將不再出現在Map
。 另一方面,如果僅在doSomething()
成功執行后從Map中刪除鍵/值對,則保證doSomething()
至少成功執行一次,以便從Map
中重新發送所有鍵/值對。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.