How can I perform a thread-safe get then remove with ConcurrentHashMap?
Solution 1
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
.
You can make this code thread safe by using the local variable to store the result of 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.
EDIT :
As commented below, this fix will not prevent doSomething()
from being called multiple times for the same key/value by different threads. 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.
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
. 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
.
Solution 2
Map.remove(key)
returns the value if it has been removed. 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.
This is not possible if you remove it first. The code above is Threadsafe, also simpler.
Rohit Manglik
EduGorilla’s CEO, Rohit Manglik harbors the yearning to revamp the ‘chalk-n-talk’ system of education and patch it with modern AI & VR powered digital learning aids. He believes that smart technologies make learning easier, faster and more interactive. And his venture EduGorilla Community Pvt. Ltd. falls in line with the same belief. Rohit graduated from NIT-Surathkal and was quite satisfied with his life. He had everything that one could ask for, a loving family, a handsomely paying job and a bunch of friends to lift his sunken spirits. But, it takes just one day, one moment and one event to change your life completely. And that day arrived in Rohit’s life a few years back when he visited his alma mater in Farrukhabad. He saw the dropped faces of his friends, listened to their issues and realized that they are not getting the high-end privileges that they deserve. It was then that he realized that some problems are so deep-rooted in the education sector of India that they cannot be changed with ease. However, Rohit Manglik is not one of those who sit comfortably on their couches and discuss the issues prevalent in society. Rather he believes in doing something for it and that is what he did. Rohit came up with a revolutionary idea to bridge the gap between educationists and students and foster a healthy dialogue among all stakeholders of education. And that is how EduGorilla came into existence. Founded in March 2016, EduGorilla is the largest EdTech startup of Uttar Pradesh and the second largest of India. It has architected a good repute among the students seeking answers to career-related issues and seeking judicious guidance. EduGorilla offers digitized course content for various competitive exams like IIT, CAT, NEET, UPSC and has captured $2.4 billion from the Indian EdTech market. It has around 200000 active subscribers, 1600000 monthly visitors, and a month-per-month growth rate of 25%. However, this journey was not easy. The leading edupreneur of Lucknow had to wait for 8-9 months to get his first seed of investment. Those were the days of hardships and struggles. He used to travel day and night pitching his idea to the investors and had even slept on railway stations. But what kept him going through the ups and downs was his devotion towards his dream. Gradually, things fell into place, his efforts paid back, and his dream venture got an identity.
Updated on June 19, 2022Comments
-
Rohit Manglik almost 2 years
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. So if thread 1 already calledchm.remove(key)
and if thread 2 came inside the if statement and is about to callget
method then we might get an exception. Is this correct?How can I make this thread-safe?
-
Erick G. Hagstrom over 8 yearsProbably be even better to just write
Integer value = chm.remove(key);
, and remove the existingchm.remove(key);
line entirely. That way thevalue
isn't lying around in the map while you're invokingdoSomething()
. -
Eran over 8 years@ErickG.Hagstrom I don't know if it's a problem that the value is
lying around in the map while you're invoking doSomething()
. Perhaps the requirement is to remove the key/value entry from the Map only afterdoSomething
is executed successfully. -
Guillaume F. over 8 yearsThis is not Threadsafe,
doSomething
can be called more than once. -
JB Nizet over 8 years@GuillaumeF. and that can be desired or not. We don't know.
-
Eran over 8 years@GuillaumeF. Yes,
doSomething
may be called more than once, but it's not necessarily a problem. My code fixes the exception that the original snippet may cause. Whether or notdoSomething
should be prevented from being called twice for the same key/value depends on the specific use case. -
Tamas Hegedus over 8 yearsSomehow I feel like the interviewer would expect this as a right answer