Thread safe container for <key, value> pair - java

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.

Related

Blocking Or NonBlocking - Adding Element during Rehashing in HashMap in Java

As given in documentation of HashMap when HashMap is full by 75%, HashMap internally performs rehashing of all existing objects.
If while performing rehashing, any element is added ->
Do we have blocking behavior of HashMap ? - Means rehashing will finish first, then element will be added.
Or
Do we have non-blocking behavior of HashMap - Means rehashing will allow adding of element in between rehashing process.
How does HashMap handles adding new element while rehashing is going on ?
From the Javadoc:
Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
You must apply external synchronization; otherwise the state of the map may get corrupted in the face of access by multiple threads.
If you are synchronizing, no other element can be added while the map is rearranging itself.
If you are not synchronizing, you are not using the class as documented, so the behaviour is undefined.
It's not blocking, but it won't "allow adding of element in between rehashing process' either. java.util.HashMap is documented to be thread unsafe. If you try to add or remove on the map while it's rehashing, you will get inconsistent behaviors.
You might want to consider using java.util.concurrent.ConcurrentHashMap.

Is iteration order over the different Collection views of a given Map guaranteed to be consistent?

For a given type of Map, are there any guarantees that iterating over the Collection views returned by the keySet, values and entries methods are iterated in the same order?
Background: I'm wondering whether transforming
public static void doSomethingForEachEntry(Map<String, Integer> someMap) {
for (String key : someMap.keySet()) {
doSomething(someMap.get(key));
}
}
to
public static void doSomethingForEachEntry(Map<String, Integer> someMap) {
for (Integer value : someMap.values()) {
doSomething(value);
}
}
is guaranteed to keep iteration order unchanged.
While it is true that you can't rely on a specific ordering unless the Map implementation explicitly defines it, there is a sentence in the API documentation that implies there is a single shared ordering for the map and all its collection views:
The order of a map is defined as the order in which the iterators on the map's collection views return their elements.
(my emphasis)
For this to be satisfied, a map has an inherent order (even though it may not be specified, and may change as the map is modified), and all collection views must correspond to this order. Whether that constitutes a guarantee, and in particular whether all third-party map implementations will honour it, is another question.
It's also worth noting that these are explicitly defined in the Map interface as views that are backed by the map, (e.g. if you remove an element from the keySet, the corresponding Map entry must be removed from the map). This means in reality it's less likely that you'll get different orderings from a correct Map implementation than it would be if for example you made shallow copies of the collection views.
Having said all that, if the question is "is this a safe refactor?" then the answer is "yes, as long as the original code isn't itself broken". If the method relies on a specific ordering, and therefore a specific Map implementation, the method should be declared to accept only that type of Map. Otherwise, you have a potential timebomb if the underlying Map implementation changes down the line (and I have seen software break in real life because of this with a JDK update).
If a particular caller is relying on a specific ordering because it knows it's passing an ordered Map implementation, that's fine and that order will be preserved after your refactor.
Iteration order depends on the specific implementation of Map you use. Refer to the documentation if you know the Map type. If you don't then don't rely on any iteration order.

HashMap and concurrency- different keys

Say I have a hash map and multiple threads. If I have a synchronized method that adds to the hash map, how would I make it possible that two different threads can put different keys simultaneously (concurrently) into the hash map?
My current implementation is a synchronized method. Would this allow two different threads to put two different keys simultaneously into the hash map?
I am using a regular hash map, not Java's concurrent hash map. I am not allowed to use a concurrent hash map.
EDIT:
I think I found a solution! I think I may have miswrote this post. Let's say that the hash map is initialized as a Integer as its key and a LinkedList as its value. In order to put a totally new key, I realize that the whole hash map has to be synchronized (i.e. locked). However, if I am trying to add another String into an already contained key's corresponding LinkedList, I can just synchronize the hash map's get method. I think this will allow multiple threads to simultaneously (concurrently) add to the LinkedLists of different, already contained keys. Please let me know if I'm wrong.
Here's a concrete example. I have a hash map hashMap that uses an Integer as its key and a LinkedList as its value. The keys 5, and 10 are already in the hash map. The key 5 contains a LinkedList of Joey, Joe, Kerry. The key 10 contains the LinkedList of Jerry, Mary, Tim. I have two threads t1 and t2. t1 wants to add Moe to the LinkedList corresponding to key 5. t2 wants to add Harry to the LinkedList corresponding to key 10. Both will be concurrently added to the hash map, since the hash map's value is only locked.
My current implementation is a synchronized method. Would this allow two different threads to put two different keys simultaneously into the hash map?
No. Only a ConcurrentHashMap or a specifically designed concurrent map would support this safely, so it's impossible for you to put two keys simultaneously into the same map from two threads.
how would I make it possible that two different threads can put different keys simultaneously (concurrently) into the hash map?
You cannot, without using ConcurrentHashMap, another ConcurrentMap implementation, or implementing your own.
The easiest answer is to use a ConcurrentHashMap, which does exactly what you're looking for.
If you can't do that (I see you edited your post after I answered), then you'll have to duplicate the same thing that ConcurrentHashMap does. No, simply synchronizing the method of a HashMap will not allow two threads to add a key-value pair at the same time, they have to wait and go one at a time.
The answer to your question is NO. Because synchronized block forces every tread to wait in the single queue. With ConcurrentHashMap you have more chances for simultaneously add, because it locks only basket where element will be inserted instead of locking whole HashMap.
However, if I am trying to add another String into an already contained key's corresponding LinkedList, I can just synchronize the hash map's get method. I think this will allow multiple threads to simultaneously (concurrently) add to the LinkedLists of different, already contained keys.
Read-only access to a HashMap is safe: you can have multiple threads call the get method with no synchronization at all and nothing breaks. If the linked lists are not shared between threads you don't need synchronization either. To be sure the threads never share a list the map key should be something specific to the thread, like an object created locally or the thread ID.
What's not safe is to let another thread modify a map or a list concurrently with a read or write. This is the use case for a read-write lock: it allows multiple concurrent reads but writes have to be exclusive.

Not thread safe methods of CuncurrentSkipListMap in 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.

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.

Categories