Java ConcurrentHashMap atomic get if present

How do you perform secure retrieval if the current operation is on a parallel hash map? (same as putIfAbsent)

Bad example, not very safe thread (check, then follow the action):

ConcurrentMap<String, SomeObject> concMap = new ... //... many putIfAbsent and remove operations public boolean setOption(String id, Object option){ SomeObject obj = concMap.get(id); if (obj != null){ //what if this key has been removed from the map? obj.setOption(option); return true; } // in the meantime a putIfAbsent may have been called on the map and then this //setOption call is no longer correct return false; } 

Another bad example might be:

  public boolean setOption(String id, Object option){ if (concMap.contains(id)){ concMap.get(id).setOption(option); return true; } return false; } 

It is desirable that there are no bottlenecks for adding, deleting and receiving operations by synchronizing them.

thanks

+4
source share
4 answers

What you are trying to do is lock the key from several operations. Only every operation is atomic. This is not an easy way to lock the key, only to lock the card.

However, in the case of β€œwhat if I delete the key,” all you can do is postpone the delete operation until the setOption function is called. The result should be the same.

It seems you are trying to solve a problem that may not need to be solved. You did not explain why calling setOption after deleting the key or when the key is waiting for deletion is bad.

+1
source

The get() method on a ConcurrentHashMap is atomic. Since this map does not allow null values, get() implements "get if present": if the result is null , there was no key.

+6
source

Do not use containsKey / get , just call get . If this method returns null , then the key was absent, otherwise the key was present, and you received the value that it was displayed during get .

From the docs:

Returns the value to which the specified key is mapped, or null if this map does not contain a mapping for the key.

Here is what your second example looks like:

 public boolean setOption(String id, Object option) { SomeObject opt = concMap.get(id); if (opt == null) return false; opt.setOption(option); return true; } 
+2
source

If you need to perform several operations on the same key in ConcurrentMap, you can use the Strip Lock method to reduce the conflict, here is an example with a Guava framework:

  private Striped<Lock> lock; public boolean setOption(String id, Object option) { try { Lock lock = concMap.get(id); lock.lock(); if (concMap.contains(id)){ concMap.get(id).setOption(option); return true; } return false; } finally { lock.unlock(); } } 

Or, since Java 8: ConcurrentMap.compute is a new atomic method, see how this is done on the key:

  concMap.compute(keyId, (key, value) -> { dosmth; ... return key; }); 

ps Possible options: ConcurrentMap.computeIfPresent (), etc.

0
source

All Articles