Synchronization for inverse view of synchronized BiMap - java

The Maps.synchronizedBiMap() method states that
it is imperative that the user manually synchronize on the returned map
when accessing any of its collection views.
Does this include the inverse() view of the BiMap? For example, if the variables are initialized as in the following example, can invoking inverse.put() from other threads be problematic (e.g. the change is not visible in a get() call on either map or inverse, even if put happened-before get)?
BiMap<Object, Object> map = Maps.synchronizedBiMap(HashBiMap.create());
BiMap<Object, Object> inverse = map.inverse();
If this is in fact a problem, is there a standard/recommended way of solving this?
// EDIT
Looking at the implementation, it seems like the inverse() of a SynchronizedBiMap is also a SynchronizedBiMap, sharing the same mutex. Does this mean the described problem is non-existent? Confirmation from a Guava Collections expert would be much appreciated ;)

No, in this case you don't have to synchronize on inversed map. You cited only a fragment of the documentation, I'll also switch original keySet() with inverse() in the example code:
Returns a synchronized (thread-safe) bimap backed by the specified bimap. In order to guarantee serial access, it is critical that all access to the backing bimap is accomplished through the returned bimap.
It is imperative that the user manually synchronize on the returned map when accessing any of its collection views:
BiMap<Long, String> map = Maps.synchronizedBiMap(
HashBiMap.<Long, String>create());
//...
BiMap<String, Long> inverse = map.inverse(); // Needn't be in synchronized block
Set<String> set = inverse.keySet(); // Needn't be in synchronized block
//...
synchronized (map) { // Synchronizing on map, not set!
Iterator<String> it = set.iterator(); // Must be in synchronized block
while (it.hasNext()) {
foo(it.next());
}
}
Failure to follow this advice may result in non-deterministic behavior.
So when you want a deterministic behavior during iteration over its views (which includes in iterating over inverse view), you have to synchronize on your instance.
In case of .inverse(), as you mentioned, it creates new synchronized bimap using same mutex object, so it synchronizes properly on methods like get or contains.

Related

Java Concurrency: HashMap Vs ConcurrentHashMap when concurrent threads only remove elements

i have a main thread that creates a HashMap, adds multiple runnable objects to it and then starts each runnable (passing the HashMap to each). The runnable removes its object from the map just before it is about to finish processing.
I would like to know if there is any reason to use a ConcurrentHashMap (rather than a HashMap) in this case - the only operation the runnables perform on the map is to remove themselves from it. Is there a concurrency consideration that necessitates the use of ConcurrentHashMap in this case?
Main thread
private final Map<Integer, Consumer> runnableMap = new HashMap<>();
Runnable runnable;
for (int i = 1; i <= NUM_RUNNABLES; i++) {
runnable = new Consumer(i, runnableMap);
runnableMap.put(i, runnable);
executionContext.execute(runnable);
}
Consumer implements Runnable
private final Integer consumerNumber;
private final Map<Integer, Consumer> runnableMap;
public Consumer(int consumerNumber, final Map<Integer, Consumer> runnableMap){
this.consumerNumber = consumerNumber;
this.runnableMap = runnableMap;
}
public void run() {
:::
// business logic
:::
// Below remove is the only operation this thread executes on the map
runnableMap.remove(consumerNumber);
}
If your reason for doing this is to track thread completion, why not use a CountdownLatch? Not sure if a HashMap can have concurrency issues only on remove, I recommend use it only if your code will not break on any possible issue, or go with a ConcurrentHashMap.
The javadoc of HashMap says:
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. (A
structural modification is any operation that adds or deletes one
or more mappings; merely changing the value associated with a key
that an instance already contains is not a structural
modification.) This is typically accomplished by synchronizing on
some object that naturally encapsulates the map.
As mentioned above, deletion is a structural change and you must use synchronization.
Furthermore, in the removeNode() method of Hashmap (which is called by the remove() method), the modCount variable is incremented, which is responsible for ConcurrentModificationException. So you might get this exception if you remove elements without synchronization.
Therefore you must use a ConcurrentHashMap.
You asked about differences between HashMap and ConcurrentHashMap, but there is an additional data structure to consider: Hashtable. There are differences and trade-offs for each. You will need to evaluate which is the best fit for your intended usage.
HashMap is unsynchronized, so if more than one thread can read from or write to it, your results will be unpredictable. HashMap also permits null as key or value.
Hashtable is synchronized, doesn't support null keys or values. From the Hashtable Javadoc:
Hashtable is synchronized. If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.
ConcurrentHashMap is thread-safe, doesn't allow null to be used as a key or value.

thread safe data structure to preserve order of insertion [duplicate]

I need a data structure that is a LinkedHashMap and is thread safe.
How can I do that ?
You can wrap the map in a Collections.synchronizedMap to get a synchronized hashmap that maintains insertion order. This is not as efficient as a ConcurrentHashMap (and doesn't implement the extra interface methods of ConcurrentMap) but it does get you the (somewhat) thread safe behavior.
Even the mighty Google Collections doesn't appear to have solved this particular problem yet. However, there is one project that does try to tackle the problem.
I say somewhat on the synchronization, because iteration is still not thread safe in the sense that concurrent modification exceptions can happen.
There's a number of different approaches to this problem. You could use:
Collections.synchronizedMap(new LinkedHashMap());
as the other responses have suggested but this has several gotchas you'll need to be aware of. Most notably is that you will often need to hold the collections synchronized lock when iterating over the collection, which in turn prevents other threads from accessing the collection until you've completed iterating over it. (See Java theory and practice: Concurrent collections classes). For example:
synchronized(map) {
for (Object obj: map) {
// Do work here
}
}
Using
new ConcurrentHashMap();
is probably a better choice as you won't need to lock the collection to iterate over it.
Finally, you might want to consider a more functional programming approach. That is you could consider the map as essentially immutable. Instead of adding to an existing Map, you would create a new one that contains the contents of the old map plus the new addition. This sounds pretty bizarre at first, but it is actually the way Scala deals with concurrency and collections
There is one implementation available under Google code. A quote from their site:
A high performance version of java.util.LinkedHashMap for use as a software cache.
Design
A concurrent linked list runs through a ConcurrentHashMap to provide eviction ordering.
Supports insertion and access ordered eviction policies (FIFO, LRU, and Second Chance).
You can use a ConcurrentSkipListMap, only available in Java SE/EE 6 or later. It is order presevering in that keys are sorted according to their natural ordering. You need to have a Comparator or make the keys Comparable objects. In order to mimik a linked hash map behavior (iteration order is the order in time in which entries were added) I implemented my key objects to always compare to be greater than a given other object unless it is equal (whatever that is for your object).
A wrapped synchronized linked hash map did not suffice because as stated in
http://www.ibm.com/developerworks/java/library/j-jtp07233.html: "The synchronized collections wrappers, synchronizedMap and synchronizedList, are sometimes called conditionally thread-safe -- all individual operations are thread-safe, but sequences of operations where the control flow depends on the results of previous operations may be subject to data races. The first snippet in Listing 1 shows the common put-if-absent idiom -- if an entry does not already exist in the Map, add it. Unfortunately, as written, it is possible for another thread to insert a value with the same key between the time the containsKey() method returns and the time the put() method is called. If you want to ensure exactly-once insertion, you need to wrap the pair of statements with a synchronized block that synchronizes on the Map m."
So what only helps is a ConcurrentSkipListMap which is 3-5 times slower than a normal ConcurrentHashMap.
Collections.synchronizedMap(new LinkedHashMap())
Since the ConcurrentHashMap offers a few important extra methods that are not in the Map interface, simply wrapping a LinkedHashMap with a synchronizedMap won't give you the same functionality, in particular, they won't give you anything like the putIfAbsent(), replace(key, oldValue, newValue) and remove(key, oldValue) methods which make the ConcurrentHashMap so useful.
Unless there's some apache library that has implemented what you want, you'll probably have to use a LinkedHashMap and provide suitable synchronized{} blocks of your own.
I just tried synchronized bounded LRU Map based on insertion order LinkedConcurrentHashMap; with Read/Write Lock for synchronization.
So when you are using iterator; you have to acquire WriteLock to avoid ConcurrentModificationException. This is better than Collections.synchronizedMap.
public class LinkedConcurrentHashMap<K, V> {
private LinkedHashMap<K, V> linkedHashMap = null;
private final int cacheSize;
private ReadWriteLock readWriteLock = null;
public LinkedConcurrentHashMap(LinkedHashMap<K, V> psCacheMap, int size) {
this.linkedHashMap = psCacheMap;
cacheSize = size;
readWriteLock=new ReentrantReadWriteLock();
}
public void put(K key, V value) throws SQLException{
Lock writeLock=readWriteLock.writeLock();
try{
writeLock.lock();
if(linkedHashMap.size() >= cacheSize && cacheSize > 0){
K oldAgedKey = linkedHashMap.keySet().iterator().next();
remove(oldAgedKey);
}
linkedHashMap.put(key, value);
}finally{
writeLock.unlock();
}
}
public V get(K key){
Lock readLock=readWriteLock.readLock();
try{
readLock.lock();
return linkedHashMap.get(key);
}finally{
readLock.unlock();
}
}
public boolean containsKey(K key){
Lock readLock=readWriteLock.readLock();
try{
readLock.lock();
return linkedHashMap.containsKey(key);
}finally{
readLock.unlock();
}
}
public V remove(K key){
Lock writeLock=readWriteLock.writeLock();
try{
writeLock.lock();
return linkedHashMap.remove(key);
}finally{
writeLock.unlock();
}
}
public ReadWriteLock getLock(){
return readWriteLock;
}
public Set<Map.Entry<K, V>> entrySet(){
return linkedHashMap.entrySet();
}
}
The answer is pretty much no, there's nothing equivalent to a ConcurrentHashMap that is sorted (like the LinkedHashMap). As other people pointed out, you can wrap your collection using Collections.synchronizedMap(-yourmap-) however this will not give you the same level of fine grained locking. It will simply block the entire map on every operation.
Your best bet is to either use synchronized around any access to the map (where it matters, of course. You may not care about dirty reads, for example) or to write a wrapper around the map that determines when it should or should not lock.
How about this.
Take your favourite open-source concurrent HashMap implementation. Sadly it can't be Java's ConcurrentHashMap as it's basically impossible to copy and modify that due to huge numbers of package-private stuff. (Why do the Java authors always do that?)
Add a ConcurrentLinkedDeque field.
Modify all of the put methods so that if an insertion is successful the Entry is added to the end of the deque. Modify all of the remove methods so that any removed entries are also removed from the deque. Where a put method replaces the existing value, we don't have to do anything to the deque.
Change all iterator/spliterator methods so that they delegate to the deque.
There's no guarantee that the deque and the map have exactly the same contents at all times, but concurrent hash maps don't make those sort of promises anyway.
Removal won't be super fast (have to scan the deque). But most maps are never (or very rarely) asked to remove entries anyway.
You could also achieve this by extending ConcurrentHashMap, or decorating it (decorator pattern).

is Treemap inside ConcurrentHashMap thread safe?

I have a case of nested maps as follows:
private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
I know that ConcurrentHashMap is thread safe, but I want to know about the TreeMaps this CHM holding, are they also thread safe inside CHM ?
The operations I am doing are:
If specific key is not found --> create new TreeMap and put against key.
If key is found then get the TreeMap, and update it.
Retrieve TreeMap from CHM using get(K).
Retreive data from TreeMap using tailMap(K,boolean) method.
clear() the CHM.
I want a thread-safe structure in this scenario. Is the above implementation thread-safe or not? If not then please suggest a solution.
Once you've done TreeMap<?, ?> tm = chm.get(key); you are not in thread safe territory any longer. In particular, if another thread updates the treemap (through the CHM or not) you may or may not see the change. Worse, the copy of the map that you have in tm may be corrupted...
One option would be to use a thread safe map, such as a ConcurrentSkipListMap.
Simple answer: no.
If your map is a ConcurrentHashMap, then all operations that affect the state of your hashmap are thread-safe. That does not at all mean that objects stored in that map become thread-safe.
How would that work; you create any kind of object, and by adding it to such a map, the object itself becomes thread-safe? And when you remove that object from the map, the "thread-unsafety" is restored?!
Assuming you're doing all of this in multiple threads, no, it's not thread-safe.
Ignore the fact that you've accessed the TreeMap via a ConcurrentHashMap - you end up with multiple threads accessing the TreeMap at the same time, including one or more of them writing to the map. That's not safe, because TreeMap isn't thread-safe for that situation:
Note that this implementation is not synchronized. If multiple threads access a map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
Some your scenarios are thread-safe, some are not:
1. Yes this is thread safe though other threads cannot see newly created TreeMap until you put it to CHM. But this should be implemented carefully to avoid race conditions - you should make it sure that checking and insertion are performed atomically:
// create an empty treemap somewhere before
TreeMap<Long, String> emptyMap = new TreeMap<>();
...
// On access, use putIfAbsent method to make sure that if 2 threads
// try to get same key without associated value sumultaneously,
// the same empty map is returned
if (outerConcurrentMap.putIfAbsent(key, emptyMap) == null) {
emptyMap = new TreeMap<>();
};
map = outerConcurrentMap.get(key);
2, 3, 4. No, you first need to lock this TreeMap by explicit lock or using synchronized. TreeMap is not synchronized by itself.
5. Yes, this is operation is performed on CHM, so it is thread-safe.
If you need fully thread-safe sorted map, use ConcurrentSkipListMap instead. It is slower than TreeMap but its internal structure doesn't need to lock full collection during access thus making it effective in concurrent environment.
The TreeMap itself should not be thread safe. Since only the methods of the ConcurrentHashMap are effected.
What you could do is following:
private final static Map<String, SortedMap <Long,String>> outerConcurrentMap= new ConcurrentHashMap<String, SortedMap <Long,String> >();
static {
// Just an example
SortedMap map = Collections.synchronizedSortedMap(new TreeMap(...));
outerConcurrentMap.put("...",map);
}

Java concurrency with a Map of Lists

I have a java class that is accessed by a lot of threads at once and want to make sure it is thread safe. The class has one private field, which is a Map of Strings to Lists of Strings. I've implemented the Map as a ConcurrentHashMap to ensure gets and puts are thread safe:
public class ListStore {
private Map<String, List<String>> innerListStore;
public ListStore() {
innerListStore = new ConcurrentHashMap<String, List<String>>();
}
...
}
So given that gets and puts to the Map are thread safe, my concern is with the lists that are stored in the Map. For instance, consider the following method that checks if a given entry exists in a given list in the store (I've omitted error checking for brevity):
public boolean listEntryExists(String listName, String listEntry) {
List<String> listToSearch = innerListStore.get(listName);
for (String entryName : listToSearch) {
if(entryName.equals(listEntry)) {
return true;
}
}
return false;
}
It would seem that I need to synchronize the entire contents of this method because if another method changed the contents of the list at innerListStore.get(listName) while this method is iterating over it, a ConcurrentModificationException would be thrown.
Is that correct and if so, do I synchronize on innerListStore or would synchronizing on the local listToSearch variable work?
UPDATE: Thanks for the responses. It sounds like I can synchronize on the list itself. For more information, here is the add() method, which can be running at the same time the listEntryExists() method is running in another thread:
public void add(String listName, String entryName) {
List<String> addTo = innerListStore.get(listName);
if (addTo == null) {
addTo = Collections.synchronizedList(new ArrayList<String>());
List<String> added = innerListStore.putIfAbsent(listName, addTo);
if (added != null) {
addTo = added;
}
}
addTo.add(entryName);
}
If this is the only method that modifies the underlying lists stored in the map and no public methods return references to the map or entries in the map, can I synchronize iteration on the lists themselves and is this implementation of add() sufficient?
You can synchronize on listToSearch ("synchronized(listToSearch) {...}"). Make sure that there is no race condition creating the lists (use innerListStore.putIfAbsent to create them).
You could synchronize on just listToSearch, there's no reason to lock the entire map any time anyone is using just one entry.
Just remember though, that you need to synchronize on the list everywhere it is modified! Synchronizing the iterator doesn't automagically block other people from doing an add() or whatnot if you passed out to them references to the unsynchronized list.
It would be safest to just store synchronized lists in the Map and then lock on them when you iterate, and also document when you return a reference to the list that the user must sycnhronize on it if they iterate. Synchronization is pretty cheap in modern JVMs when no actual contention is happening. Of course if you never let a reference to one of the lists escape your class, you can handle it internally with a finer comb.
Alternately you can use a threadsafe list such as CopyOnWriteArrayList that uses snapshot iterators. What kind of point in time consistency you need is a design decision we can't make for you. The javadoc also includes a helpful discussion of performance characteristics.
It would seem that I need to synchronize the entire contents of this method because if another method changed the contents of the list at innerListStore.get(listName) while this method is iterating over it, a ConcurrentModificationException would be thrown.
Are other threads accessing the List itself, or only though operations exposed by ListStore?
Will operations invoked by other threads result in the contents of the a List stored in the Map being changed? Or will entries only be added/removed from the Map?
You would only need to synchronize access to the List stored within the Map if different threads can result in changes to the same List instances. If the threads are only allowed to add/remove List instances from the Map (i.e. change the structure of the Map), then synchronization is not necessary.
if the lists stored in the map are of the type that don't throw CME (CopyOnWriteArrayList for example) you can iterate at will
this can introduce some races though if you're not careful
If the Map is already thread safe, then I think syncronizing the listToSearch should work. Im not 100% but I think it should work
synchronized(listToSearch)
{
}
You could use another abstraction from Guava
Note that this will synchronize on the whole map, so it might be not that useful for you.
As you haven't provided any client for the map of lists apart from the boolean listEntryExists(String listName, String listEntry) method, I wonder why you are storing lists at all? This structure seems to be more naturally a Map<String, Set<String>> and the listEntryExists should use the contains method (available on List as well, but O(n) to the size of the list):
public boolean listEntryExists(String name, String entry) {
SetString> set = map.get(name);
return (set == null) ? false : set.contains(entry;
}
Now, the contains call can encapsulate whatever internal concurrency protocol you want it to.
For the add you can either use a synchronized wrapper (simple, but maybe slow) or if writes are infrequent compared to reads, utilise ConcurrentMap.replace to implement your own copy-on-write strategy. For instance, using Guava ImmutableSet:
public boolean add(String name, String entry) {
while(true) {
SetString> set = map.get(name);
if (set == null) {
if (map.putIfAbsent(name, ImmutableSet.of(entry))
return true
continue;
}
if (set.contains(entry)
return false; // no need to change, already exists
Set<String> newSet = ImmutableSet.copyOf(Iterables.concat(set, ImmutableSet.of(entry))
if (map.replace(name, set, newSet)
return true;
}
}
This is now an entirely thread-safe lock-free structure, where concurrent readers and writers will not block each other (modulo the lock-freeness of the underlying ConcurrentMap implementation). This implementation does have an O(n) in its write, where your original implementation was O9n) in the read. Again if you are read-mostly rather than write-mostly this could be a big win.

Is static initialized unmodifiableCollection.get guaranteed immutable?

Is static initialized unmodifiableCollection.get guaranteed immutable?
For:
static final Map FOO =
Collections.unmodifiableMap(new HashMap());
Can multiple threads use method get and not run into problems?
Even through items in FOO cannot be added/removed, what's stopping the get method from manipulating FOO's internal state for caching purposes, etc. If the internal state is modified in any way then FOO can't be used concurrently. If this is the case, where are the true immutable collections in java?
Given the specific example:
static final Map FOO = Collections.unmodifiableMap(new HashMap());
Then FOO will be immutable. It will also never have any elements. Given the more general case of:
static final Map BAR = Collections.unmodifiableMap(getMap());
Then whether or not this is immutable is entirely dependent on whether or not someone else can get to the underlying Map, and what type of Map it is. For example, if it is a LinkedHashMap then the underlying linked list could be modified by access order, and could change by calling get(). The safest way (using non-concurrent classes) to do this would be:
static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));
The javadocs for HashMap imply that so long as you make no structural changes to the map, then it is safe to use it concurrently, so this should be safe for any of the accessors that you can use, that is getting the various sets and iterating over them and get() should then be safe.
If you can use the concurrent classes, then you could also do:
static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());
This will be explicitly safe to use from multiple threads, since ConcurrentHashMap is explicitly multi-thread access safe. The internal state might be mutable, but the externally visible state will not be, and since the class is guaranteed to be threadsafe, we can safely consider it to be externally immutable.
At the risk of sounding like I'm on an advertising spree, use the Google Immutable Collections and be done with it.
Actually a good question. Think WeakHashMap - that can change without having a mutation operation called on it. LinkedHashMap in access-order mode is much the same.
The API docs for HashMap state:
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. (A structural
modification is any operation that
adds or deletes one or more mappings;
merely changing the value associated
with a key that an instance already
contains is not a structural
modification.)
Presumably that should be if and only if. That means that get does not need to be synchronised if the HashMap is 'effectively immutable'.
There is no true immutable map in Java SDK. All of the suggested Maps by Chris are only thread safe. The unmodifiable Map is not immutable either since if the underlying Map changed there will ConcurrentModificationException as well.
If you want the truly immutable map, use ImmutableMap from Google Collections / Guava.
I would suggest for any threaded operation to use ConcurrentHashMap or HashTable, both are thread-safe.
Whether a getter on the returned map happens to twiddle with some internal state is unimportant, as long as the object honors its contract (which is to be a map that cannot be modified). So your question is "barking up the wrong tree".
You are right to be cautious of UnmodifiableMap, in the case where you do not have ownership and control over the map it wraps. For example
Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!

Categories

Resources