簡體   English   中英

如何執行線程安全獲取然后使用ConcurrentHashMap刪除?

[英]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.

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