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.
Related
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).
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);
}
I have a query regarding ConcurrentHashMap.
ConcurrentHashMap is a map for concurrent access. ConcurrentHashMap implements ConcurrentMap which extends Map.
a) ConcurrentHashMap implements the methods defined in ConcurrentMap (like putifAbsent etc) which are atomic.
b) But, how about the methods in the Map interface which ConcurrentMap extends?
How are they now atomic? Have they been reimplemented by ConcurrentHashMap
If I have a reference of type ConcurrentHashMap and call a method from
the Map Interface(e.g put) or any other method, is that method an atomic method?
ConcurrentHashMap does not extend HashMap. They are both implementations of a hash table, but ConcurrentHashMap has very different internals to HashMap in order to provide concurrency.
If you provide a ConcurrentHashMap to a method that accepts Map, then that will work, and you will get the concurrent behaviour you expect. Map is simply an interface that describes a set of methods, ConcurrentHashMap implements that interface with concurrent behaviour.
There is a difference between 'concurrent' and 'atomic'. Concurrent means that multiple operations can happen at the same time and the Map (or whatever data structure we are talking about) will ALWAYS BE IN A VALID STATE. This means that you can have multiple threads calling put(), get(), remove(), etc on this map and there will never be any errors (if you try this with a regular HashMap you WILL get errors as it isn't designed to handle concurrency).
Atomic means that an action that takes multiple steps appears to take a single step to other threads - as fair as they are aware it has completely finished or hasn't even started yet. For ConcurrentHashMap, putIfAbsent() is one such example. From the javadoc,
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.
If you tried the above code with a ConcurrentHashMap, you wouldn't get any errors (since it is Concurrent), but there is a good change that other threads would interleave with the main thread and your entry would get overwritten or removed. ConcurrentMap specifies the atomic putIfAbsent() method to ensure that implementations can perform those steps atomically, without interference from other threads.
Map is just an interface. Therefore the ConcurrentHashMap has an atomic implementation of those methods.
The putIfAbsent method is a convenient way in a concurrent environment to execute an atomic if not contains then put that you cannot do from the Map interface even though the Map is actually of type ConcurrentHashMap.
The implementation of these methods like put() and remove() are getting the lock on the final Sync object, concurrent retrieval will always give the most recent data on the map.
In case of putAll() or clear(), which operates on whole Map, concurrent read may reflect insertion and removal of only some entries.
Below Two links will help you to understand:
http://javarevisited.blogspot.in/2013/02/concurrenthashmap-in-java-example-tutorial-working.html
http://www.javamex.com/tutorials/synchronization_concurrency_8_hashmap2.shtml
I have a map. Lets say:
Map<String, Object> map = new HashMap<String, Object>();
Multiple threads are accessing this map, however each thread accesses only its own entries in the map. This means that if thread T1 inserts object A into the map, it is guaranteed that no other thread will access object A. Finally thread T1 will also remove object A.
It is guaranteed as well that no thread will iterate over the map.
Does this map need to be synchronized? If yes how would you synchronize it? (ConcurrentHashMap, Collections.synchronizedMap() or synchronized block)
Yes, you would need synchronization, or a concurrent map. Just think about the size of the map: two threads could add an element in parallel, and both increment the size. If you don't synchronize the map, you could have a race condition and it would result in an incorrect size. There are many other things that could go wrong.
But you could also use a different map for each thread, couldn't you?
A ConcurrentHashMap is typically faster that a synchronized HashMap. But the choice depends on your requirements.
If you're sure that there's only one entry per thread and none thread iterates/searches through the map, then why do you need a map?
You can use ThreadLocal object instead which will contain thread-specific data. If you need to keep string-object pairs, you can create an special class for this pair, and keep it inside ThreadLocal field.
class Foo {
String key;
Object value;
....
}
//below was your Map declaration
//Map<String, Object> map = ...
//Use here ThreadLocal instead
final ThreadLocal<Foo> threadLocalFoo = new ThreadLocal<Foo>();
...
threadLocalFoo.set(new Foo(...));
threadLocalFoo.get() //returns your object
threadLocalFoo.remove() //clears threadLocal container
More info on ThreadLocals you can find in ThreadLocal javadocs.
I would say that yes. Getting the data is not the issue, adding the data is.
The HashMap has a series of buckets (lists); when you put data to the HashMap, the hashCode is used to decide in which bucket the item goes, and the item is added to the list.
So it can be that two items are added to the same bucket at the same time and, due to some run condition, only one of them is effectively stored.
You have to synchronize writing operations in the map. If after initializating the map, no thread is going to insert new entries, or delete entries in the map you don't need to synchronize it.
However, in your case (where each thread has its own entry) I'd recommend using ThreadLocal, which allows you to have a "local" object which will have different values per thread.
Hope it helps
For this scenario I think ConcurrentHashMap is the best Map, because both Collections.synchronizedMap() or synchronized block (which are basically the same) have more overhead.
If you want to insert entries and not only read them in different threads you have to synchronize them because of the way the HashMap works.
- First of all its always a practice to write a Thread-safe code, specially in cases like the above, not in all conditions.
- Well its better to use HashTable which is a synchronized Map, or java.util.concurrent.ConcurrentHashMap<K,V>.
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!