简体   繁体   English

如何执行线程安全获取然后使用ConcurrentHashMap删除?

[英]How can I perform a thread-safe get then remove with ConcurrentHashMap?

In an interview, I was asked to check whether following code works as intended. 在一次采访中,我被要求检查以下代码是否按预期工作。

ConcurrentHashMap<Integer, Integer> chm = new ConcurrentHashMap<>();

if (chm.get(key) != null) {
    chm.get(key).doSomething();
    chm.remove(key);
}

According to JavaDocs, get returns value of last completed update operation. 根据JavaDocs, get上次完成的更新操作的返回值。 So if thread 1 already called chm.remove(key) and if thread 2 came inside the if statement and is about to call get method then we might get an exception. 因此,如果线程1已经调用了chm.remove(key)并且如果线程2进入if语句并且即将调用get方法,那么我们可能会得到一个异常。 Is this correct? 它是否正确?

How can I make this thread-safe? 我怎样才能使这个线程安全?

Map.remove(key) returns the value if it has been removed. 如果已删除,则Map.remove(key)返回值。 This is a very good trick in many situations, including yours: 在许多情况下,这是一个非常好的技巧,包括你的:

Object value = chm.remove(key)
if(value != null)
{
     value.doSomething();
}

You can't work safely with a get then a remove because if two threads call your method at the same time, there's always a risk they call doSomething two or more times, before the key has been removed. 你不能安全地使用get然后删除,因为如果两个线程同时调用你的方法,那么在删除密钥之前,他们总是存在两次或多次调用doSomething的风险。

This is not possible if you remove it first. 如果先将其删除,则无法进行此操作。 The code above is Threadsafe, also simpler. 上面的代码是Threadsafe,也更简单。

You are correct. 你是对的。 If this Map can be modified by multiple threads, it's possible that the first call to chm.get(key) will return a non-null value and the second call will return null (due to the removal of the key from the Map done by another thread), and thus chm.get(key).doSomething() will throw a NullPointerException . 如果这个Map可以被多个线程修改,那么对chm.get(key)的第一次调用可能会返回一个非null值,而第二次调用将返回null (由于从Map完成的Map删除了键)另一个线程),因此chm.get(key).doSomething()将抛出一个NullPointerException

You can make this code thread safe by using the local variable to store the result of chm.get(key) : 您可以使用局部变量来存储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);
}

BTW, even if that Map wasn't a ConcurentHashMap and only one thread had access to it, I'd still use a local variable, since it's more efficient than calling the get() method twice. 顺便说一句,即使Map不是ConcurentHashMap并且只有一个线程可以访问它,我仍然使用局部变量,因为它比调用get()方法两次更有效。

EDIT : 编辑:

As commented below, this fix will not prevent doSomething() from being called multiple times for the same key/value by different threads. 如下面所述,此修复程序不会阻止doSomething()被不同的线程多次调用相同的键/值。 Whether or not that's the desired behavior is not clear. 这是否是所期望的行为并不清楚。

If you wish to prevent the possiblity of doSomething() being called by multiple threads for the same key/value, you can use chm.remove(key) for both removing the key and obtaining the value at the same step. 如果您希望防止多个线程为同一个键/值调用doSomething() chm.remove(key) ,您可以使用chm.remove(key)来删除键并在同一步骤获取值。

This however runs the risk that doSomething() will not be executed at all for some key/value, since if the first call to doSomething() resulted in an exception, there won't be another call to doSomething() by another thread, since the key/value pair will no longer be in the Map . 然而,这会冒一些键/值根本不会执行doSomething()的风险,因为如果第一次调用doSomething()导致异常,则不会再由另一个线程调用doSomething() ,因为键/值对将不再出现在Map On the other hand, if you remove the key/value pair from the Map only after doSomething() executes succesfully, you guarantee that doSomething() is executed successfuly at least once for all the key/value pairs that were reomved from the Map . 另一方面,如果仅在doSomething()成功执行后从Map中删除键/值对,则保证doSomething()至少成功执行一次,以便从Map中重新发送所有键/值对。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何测试ConcurrentHashMap是否真的是线程安全的? - How can I test that ConcurrentHashMap is truly thread-safe? ConcurrentHashMap put() 方法可以不是线程安全的吗? - Can ConcurrentHashMap put() method be not thread-safe? 在ConcurrentHashMap上进行此操作是否线程安全? - Is it Thread-safe on this operating on ConcurrentHashMap? 如何使此代码线程安全 - How can I make this code thread-safe 如何实现或找到线程安全的CompletionService的等效项? - How can I implement or find the equivalent of a thread-safe CompletionService? CopyOnWriteArrayList 如何是线程安全的? - How can CopyOnWriteArrayList be thread-safe? 在ConcurrentHashMap中放置线程安全的同时增加当前值? - Is incrementing of current value while putting thread-safe in ConcurrentHashMap? 这个字典是否是线程安全的(ConcurrentHashMap + AtomicInteger)? - Is this dictionary function thread-safe (ConcurrentHashMap+AtomicInteger)? ThreadLocal HashMap vs ConcurrentHashMap用于线程安全的未绑定缓存 - ThreadLocal HashMap vs ConcurrentHashMap for thread-safe unbound caches 我可以将 ConcurrentHashMap 与 Integer 一起用于线程安全计数器吗? - Can I use ConcurrentHashMap with Integer for thread safe counters?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM