Not thread safe methods of CuncurrentSkipListMap in Java - java

In my Java project I need to use TreeMap in multihreaded way. I found that ConcurrentSkipListMap is what that I need but some methods are not thread safe. One of them - containsKey(Object key). What is a typical solution for using this methods in multhreded way? In my program I need put key that will not replace old and if it's impossible I will be putting another key while will not get unique key. What construction should use instead containsKey as i can't lost information?

If you are worried about containsKey results going stale before you can act on them, or about this warning in the javadoc:
Additionally, the bulk operations putAll, equals, toArray, containsValue, and clear are not guaranteed to be performed atomically. For example, an iterator operating concurrently with a putAll operation might view only some of the added elements.
there are methods defined on ConcurrentSkipListMap that you can use instead. For instance, see putIfAbsent:
If the specified key is not already associated with a value, associate it with the given value. This is equivalent to
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
except that the action is performed atomically.
Also see the methods remove and replace.

Related

Confused about HashMap in Java8

I have a hashmap that takes String and HashSet as key and values.
I am trying to update the map and add values in it.
I cannot understand which of the following methods to use-
map.putIfAbsent(str.substring(i,j),new HashSet<String>).add(str);
//this method gives nullpointerexception
map.computeIfPresent(str.substring(i,j),(k,v)->v).add(str);
In the output I can see the same key being added twice with an initial value and updated value.
Someone please tell me how to use these methods.
The preferable way to do it is with Map#computeIfAbsent. This way a new HashSet is not created unnecessarily, and it will return the value afterwards.
map.computeIfAbsent(str.substring(i, j), k -> new HashSet<>()).add(str);
There is no reason to choose between putIfAbsent and computeIfPresent. Most notably, computeIfPresent in entirely inappropriate as it, as its name suggests, only computes a new value, when there is already an old one, and (k,v)->v even makes this computation a no-op.
There are several options
containsKey, put and get. This is the most popular pre-Java 8 one, though its the most inefficient of this list, as it incorporates up to three hash lookups for the same key
String key=str.substring(i, j);
if(!map.containsKey(key))
map.put(key, new HashSet<>());
map.get(key).add(str);
get and put. Better than the first one, though it still may incorporate two lookups. For ordinary Maps, this was the best choice before Java 8:
String key=str.substring(i, j);
Set<String> set=map.get(key);
if(set==null)
map.put(key, set=new HashSet<>());
set.add(str);
putIfAbsent. Before Java 8, this option was only available to ConcurrentMaps.
String key=str.substring(i, j);
Set<String> set=new HashSet<>(), old=map.putIfAbsent(key, set);
(old!=null? old: set).add(str);
This only bears one hash lookup, but needs the unconditional creation of a new HashSet, even if we don’t need it. Here, it might be worth to perform a get first to defer the creation, especially when using a ConcurrentMap, as the get can be performed lock-free and may make the subsequent more expensive putIfAbsent unnecessary.
On the other hand, it must be emphasized, that this construct is not thread-safe, as the manipulation of the value Set is not guarded by anything.
computeIfAbsent. This Java 8 method allows the most concise and most efficient operation:
map.computeIfAbsent(str.substring(i, j), k -> new HashSet<>()).add(str);
This will only evaluate the function, if there is no old value, and unlike putIfAbsent, this method returns the new value, if there was no old value, in other words, it returns the right Set in either case, so we can directly add to it. Still, the add operation is performed outside the Map operation, so there’s no thread safety, even if the Map is thread safe. But for ordinary Maps, i.e. if thread safety is not a concern, this is the most efficient variant.
compute. This Java 8 method will always evaluate the function and can be used in two ways. The first one
map.compute(str.substring(i, j), (k,v) -> v==null? new HashSet<>(): v).add(str);
is just a more verbose variant of computeIfAbsent. The second
map.compute(str.substring(i, j), (k,v) -> {
if(v==null) v=new HashSet<>();
v.add(str);
return v;
});
will perform the Set update under the Map’s thread safety policy, so in case of ConcurrentHashMap, this will be a thread safe update, so using compute instead of computeIfAbsent has a valid use case when thread safety is a concern.

Thread safe container for <key, value> pair

I need a container that contains [key, Value] pair.
Here, key = Integer, Value = User Defined class object.
Mutiple threads are trying to add [key, Value] pair in above container.
If key already present in the container, I want to update the value by checking some condition.
At the end I want container in sorted order, according to Key.
My efforts -
I used this synchronizedSortedMap and Sorted Map for above task.
SortedMap<Integer, USER_DEFINED_OBJECT> m = Collections.synchronizedSortedMap(new TreeMap<Integer, USER_DEFINED_OBJECT>());
This helps me to add pairs concurrently on above container.
And, yes If key already present, then I check some condition, then proceed.
Is my approach always thread safe ? If not, please correct me.
Updated
USER_DEFINED_OBJECT has some field index.
At the time of adding, I am checking if key is already present, then compare current USER_DEFINED_OBJECT with already present USER_DEFINED_OBJECT on the basis of above mentioned(in point 1) filed "index". If currect "index" is greater than update.
Use ConcurrentHashMap from java.util package, read the API ConcurrentHashMap
java.util.concurrent.ConcurrentSkipListMap
A scalable concurrent ConcurrentNavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
This class implements a concurrent variant of SkipLists providing expected average log(n) time cost for the containsKey, get, put and remove operations and their variants. Insertion, removal, update, and access operations safely execute concurrently by multiple threads. Iterators are weakly consistent, returning elements reflecting the state of the map at some point at or since the creation of the iterator. They do not throw ConcurrentModificationException, and may proceed concurrently with other operations. Ascending key ordered views and their iterators are faster than descending ones.
The concurrent collections let you call methods like put, remove etc. in kind of transaction. Therefore it's thread safe.
From what I understood your scenario for adding new [key, value] pair is as follows:
Check whether the mapping already exists
If not, just add it
If yes, update the existing value in the mapping based on some check
I doubt there is an implementation in place which does this for you in thread-safe way. In the case I understood your use-case correctly you will need to add some manual synchronization on your own to make the update steps transactional.

Atomic way to reorder keys in a ConcurrentSkipListMap / ConcurrentSkipListSet?

Summary of this post: I have an set of ordered items whose order may change over time. I need to be able to iterate through this set from multiple threads, each of which may also want to update the order of the items.
For example, multiple threads need to access String keys in some arbitrary sorted order. They strings are not sorted according to their natural ordering, but by some values that may change (hence, a custom Comparator). My original implementation was to use a TreeSet and synchronize on it. If any of the keys needed to be reordered, a thread would remove the key from the map, update the comparison value, and reinsert the key. To implement this, the keys are native Strings, but the comparator has access to the values. This is a weird arrangement where the order of keys may change over time, but since a changed key is always removed and reinserted when it changes, it seems to work. (I suppose it could also work if the Strings were wrapped inside another object.)
I recently became aware of the ConcurrentSkipListSet/ConcurrentSkipListMap implementations which are basically thread-safe sorted sets (resp. maps.) It seems like I can now iterate through the keys without having to lock the entire data structure. However, is there a way I can use them to atomically remove a key and replace it with another, like the operation I was doing above, so that other iterating threads don't miss the item, and without having to use synchronize blocks?
If anyone can suggest a better data structure for this type of operation, I'm all ears, too!
is there a way I can use them to atomically remove a key and replace it with another, like the operation I was doing above, so that other iterating threads don't miss the item, and without having to use synchronize blocks?
The short answer is no. If you need to remove and reinsert, there is no atomic way to do this with any collection that I know of.
That said, one possibility would be for you to reinsert the item before deleting it from the skip list. This would cause a duplicate but may be easier to handle then a missing entry. You would reinsert it after you changed the object so it would sort differently. This assumes that the object would then be non-equal as well. But if the other threads that are processing the lists can't handle the duplicates then I think you are SOL.

Is there an atomic "set if empty" operation in anyof the Map Sub classes?

I have to implement logic where I need to atomically set an object for a key only if the key is currently not mapped to any value. I can implement this myself but don't want to reinvent the wheel if it's already been done somewhere.
ConcurrentHashMap has putIfAbsent method, may be it's what you need. And as dogbane pointed out, thit is actually defined in base interface ConcurrentMap, so ConcurrentSkipListMap has it too.
Use ConcurrentHashMap.putifAbsent
If the specified key is not already associated with a value, associate
it with the given value. This is equivalent to
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
except that the action is performed atomically.

Is there a Java Collection (or similar) that behaves like an auto-id SQL table?

Note that I'm not actually doing anything with a database here, so ORM tools are probably not what I'm looking for.
I want to have some containers that each hold a number of objects, with all objects in one container being of the same class. The container should show some of the behaviour of a database table, namely:
allow one of the object's fields to be used as a unique key, i. e. other objects that have the same value in that field are not added to the container.
upon accepting a new object, the container should issue a numeric id that is returned to the caller of the insertion method.
Instead of throwing an error when a "duplicate entry" is being requested, the container should just skip insertion and return the key of the already existing object.
Now, I would write a generic container class that accepts objects which implement an interface to get the value of the key field and use a HashMap keyed with those values as the actual storage class. Is there a better approach using existing built-in classes? I was looking through HashSet and the like, but they didn't seem to fit.
None of the Collections classes will do what you need. You'll have to write your own!
P.S. You'll also need to decide whether your class will be thread-safe or not.
P.P.S. ConcurrentHashMap is close, but not exactly the same. If you can subclass or wrap it or wrap the objects that enter your map such that you're relying only on that class for thread-safety, you'll have an efficient and thread-safe implementation.
You can simulate this behavior with a HashSet. If the objects you're adding to the collection have a field that you can use as a unique ID, just have that field returned by the object's hashCode() method (or use a calculated hash code value, either way should work).
HashSet won't throw an error when you add a duplicate entry, it just returns false. You could wrap (or extend) HashSet so that your add method returns the unique ID that you want as a return value.
I was thinking you could do it with ArrayList, using the current location in the array as the "id", but that doesn't prevent you from making an insert at an existing location, plus when you insert at that location, it will move everything up. But you might base your own class on ArrayList, returning the current value of .size() after a .add.
Is there a reason why the object's hash code couldn't be used as a "numeric id"?
If not, then all you'd need to do is wrap the call into a ConcurrentHashMap, return the object's hashCode and use the putIfAbsent(K key, V value) method to ensure you don't add duplicates.
putIfAbsent also returns the existing value, so you could get its hashCode to return to your user.
See ConcurrentHashMap

Categories