I wanted to use Collection for only single threaded environment and I am using a HashMap that is synchronized.
However, I still doubt if it is thread safe to have it synchronized or not.
If you're only using a single thread, you don't need a thread-safe collection - HashMap should be fine.
You should be very careful to work out your requirements:
If you're really using a single thread, stick with HashMap (or consider LinkedHashMap)
If you're sharing the map, you need to work out what kind of safety you want:
If the map is fully populated before it's used by multiple threads, which just read, then
HashMap is still fine.
Collections.synchronizedMap will only synchronize each individual operation; it still isn't
safe to iterate in one thread and modify the map in another thread without synchronization.
ConcurrentHashMap is a more "thoroughly" thread-safe approach, and one I'd generally prefer
over synchronizedMap. It allows for modification during iteration, but doesn't guarantee
where such modifications will be seen while iterating. Also note that while HashMap allows null
keys and values, ConcurrentHashMap doesn't.
For your needs, use ConcurrentHashMap. It allows concurrent modification of the Map from several threads without the need to block them. Collections.synchronizedMap(map) creates a blocking Map which will degrade performance, albeit ensure consistency
the standard java HashMap is not synchronized.
If you are in a single threaded environment you don't need to worry about synchronization.
The commonly used Collection classes, such as java.util.ArrayList, are not synchronized. However, if there's a chance that two threads could be altering a collection concurrently, you can generate a synchronized collection from it using the synchronizedCollection() method. Similar to the read-only methods, the thread-safe APIs let you generate a synchronized collection, list, set, or map. For instance, this is how you can generate a synchronized map from a HashMap:
Map map = Collections.synchronizedMap(new HashMap());
map.put(...
As its a single-threaded environment you can safely use HashMap.
Related
Our legacy multi-threaded application has a lots of usage of Hashtable. Is it safe to replace the Hashtable instances with ConcurrentHashmap instances for performance gain? Will there be any side effect?
Is it safe to replace the Hashtable instances with ConcurrentHashmap instances for performance gain?
In most cases it should be safe and yield better performance. The effort on changing depends on whether you used the Map interface or Hashtable directly.
Will there be any side effect?
There might be side effects if your application expects to immediately be able to access elements that were put into the map by another thread.
From the JavaDoc on ConcurrentHashMap:
Retrieval operations (including get) generally do not block, so may overlap
with update operations (including put and remove). Retrievals reflect the
results of the most recently completed update operations holding upon their onset.
Edit: to clarify on "immediately" consider thread 1 adds element A to the map and while that write is executed thread 2 tries to whether A exists in the map. With Hashtable thread 2 would be blocked until after the write so the check would return true but when using ConcurrentHashMap it would return false since thread 2 would not be blocked and the write operation is not yet completed (thus thread 2 would see an outdated version of the bucket).
Depending on the size of your Hashtable objects you might get some performance gains by switching to ConcurrentHashmap.
ConcurrentHashmap is broken into segments which allow for the table to be only partially locked. This means that you can get more accesses per second than a Hashtable, which requires that you lock the entire table.
The tables themselves are both thread safe and both implement the Map interface, so replacement should be relatively easy.
Map<String,Integer> m1 = new ConcurrentHashMap<>();
Map<String,Integer> m2 = new ConcurrentHashMap<>();
public void update(int i) {
m1.put("key", i);
m2.put("key", i);
}
In the dummy code above, the updates to m1 & m2 are not atomic. If I try to synchronize this block, findBugs complains "Synchronization performed on util.concurrent instance"
Is there a recommended way to do this other than not using concurrent collections and doing all synchronization explicitly.
As an aside I also don't know the exact implications of wrapping concurrent collections in explicit synchronization.
If the intention is that for a key both maps always retrieve the same value, the design of using two different concurrent maps is flawed. Even if you synchronize the write, reading threads can still access the two maps while youre writing. Thats probably what the FindBugs rule tries to catch.
There are two ways to go about this, either use explicit synchronization (that is two regular maps with synchronized reads and writes), or use just one concurrent map and put in a value object hold both ints.
A ConcurrentMap is not a synchronized map. The latter does indeed synchronizes on itself, so synchronizing on the Map will have an effect regarding other Map operations.
In contrast, a ConcurrentMap is designed to allow concurrent updates of different keys and does not synchronizes on itself, so if other code synchronizes on the Map instance, it has no effect. It wouldn’t help to use a different mutex; as long as other thread perform operations on the same maps without using this mutex, they won’t respect you intended atomicity. On the other hand, if all threads would use the mutex for all accesses to the maps, you wouldn’t need a ConcurrentMap anymore.
But as Jarrod Roberson noted, this is likely an X-Y Problem, as updating two maps atomically without having an atomic read of both maps, no thread would notice whether the update happened atomically or not. The question is what you actually want to achieve, either, you don’t really need the atomicity or you shouldn’t use ConcurrentMaps.
[Question]: Is it thread safe to use ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>> or not.
[Optional to answer]: Also what about another concurrent maps types? And what about concurrent collections?
P.S. I'm asking only about java.util.concurrent package.
Specific Usage Context:
//we have
ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>> map = new ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>>();
//each string can be executed separately and concurently
ConcurrentHashMap<Object, Object> subMap = new ConcurrentHashMap<Object, Object>()
map.put(key, subMap);
map.remove(key);
map.get(key);
map.get(key).put(key, ref);
map.get(key).remove(key);
Maybe my solution lays around Guava HashBasedTable?
You can't define thread safety without the specific context in which you plan to use your collections.
The concurrent collections you have named are thread-safe on their own in the sense that their internal invariants will not be broken by concurrent access; however that's just one bullet point on the thread safety checklist.
If you perform anything more than a single operation on your structure, which must be atomic as a whole, then you will not get thread safety just by using these classes. You will have to resort to classic locking, or some quite elaborate, and usually unmotivated, lock-free updating scheme.
Using the examples from your question, consider the following.
Thread 1 executes
map.get(mapKey).put(key, value);
At the same time, Thread 2 executes
map.remove(mapKey);
What is the outcome? Thread 1 may be putting something to a map which has already been removed, or it may even get a null result from get. In most cases more coordination will be needed for correctness.
Concurrent Collections means multiple thread could perform add/remove operation on collection same time, No it is not thread safe
More Detail:
for further please read
What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map)?
Is ConcurrentHashMap totally safe?
The concurrent collections are thread safe for reads; but you must expect ConcurrentModificationException in case of competing concurrent updates or when modifying a Collection while another thread is iterating over it.
this is what the javadoc of ConcurrentHashMap says:
However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access
So, they ARE thread-safe in terms of modifying it.
UPDATE
same javadoc http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html says:
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove). Retrievals reflect the results of the most recently completed update operations holding upon their onset. For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.
In general the classes which are part of java.util.concurrent provide additional performance at the (potential) penalty of additional coding complexity.
The issue that I see with nesting ConcurrentMap instances is managing the populating the outer map with values at given keys. If all the keys are known upfront and values placed in the map in some sort of initialization phase, there are no issues (but you also likely would not need to have the outer map be a ConcurrentMap). If you need to be able to insert new maps into the outer map as you go, the work becomes a bit more complicated. When creating a new map to insert into the outer map, you would need to use the putIfAbsentmethod[1] and pay attention to the returned value to determine what instance to add data to.
[1] - http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K,%20V)
I need to use a HashMap of the form <String, ArrayList<String>> that is going to be
accessed by several different threads. From what I've managed to understand, ConcurrentHashMap is the preferred method. But will there be any problem with the fact that the value of the map is an ArrayList? Do I have to define the value as a synchronized ArrayList or something like that?
yes, there can be a problem. The ConcurrentHashMap will be thread safe for accesses into the Map, but the Lists served out need to be thread-safe, if multiple threads can operate on the same List instances concurrently.
So use a thread-safe list if that is true.
Edit -- now that i think about it, the rabbit-hole goes further. You have your Map, you have your List, and you have the objects in the list. Anything multiple threads can modify should be thread safe. So if many threads can modify the Map, Lists, and Objects in the Lists, then all of those should have thread-safety guards. If only the Map and List instances can be modified concurrently, only they need thread safety. If multiple threads can read everything, but not modify, then you don't need any thread safety (I think, someone will correct me if this is wrong)
ConcurrentHashMap guarantees atomicity in its mutating methods e.g. putIfAbsent, computeIfAbsent, computeIfPresent so if all the modification is done through these methods no problems will arise.
But at the same time, multiple threads can read the same map entry (concurrent reads are allowed). therefore multiple threads can access and modify an unsafe collection (map value)
I am really confused on how these 2 collections behave in multithreaded environment.
Hash table is synchronized that means no 2 threads will be updating its value simultaneously right?
Look at ConcurrentHashMaps for Thread safe Maps.
They offer all the features of HashTable with a performance very close to a HashMap.
Performance is gained by instead of using a map wide lock, the collection maintains a list of 16 locks by default, each of which is used to lock a single bucket of the map. You can even configure the number of buckets :) Tweaking this can help performance depending on your data.
I can't recommend enough Java Concurrency in Practice by Brian Goetz
http://jcip.net/
I still learn something new every time I read it.
Exactly, HashTable is synchronized that mean that it's safe to use it in multi-thread environment (many thread access the same HashTable) If two thread try to update the hashtable at the sametime, one of them will have to wait that the other thread finish his update.
HashMap is not synchronized, so it's faster, but you can have problem in a multi-thread environment.
Also note that Hashtable and Collections.synchronizedMap are safe only for individual operations. Any operations involving multiple keys or check-then-act that need to be atomic will not be so and additional client side locking will be required.
For example, you cannot write any of the following methods without additional locking:
swap the values at two different keys: swapValues(Map, Object k1, Object k2)
append the parameter to value at a key: appendToValue(Map, Object k1, String suffix)
And yes, all of this is covered in JCIP :-)
Yes, all the methods are done atomically, but values() method not (see docs).
Paul was faster than me recommending you the java.util.concurrent package, which gives you a very fine control and data structures for multithreade environments.
Hashtables are synchronized but they're an old implementation that you could almost say is deprecated. Also, they don't allow null keys (maybe not null values either? not sure).
One problem is that although every method call is synchronized, most interesting actions require more than one call so you have to synchronize around the several calls.
A similar level of synchronization can be obtained for HashMaps by calling:
Map m = Collections.synchronizedMap(new HashMap());
which wraps a map in synchronized method calls. But this has the same concurrency drawbacks as Hashtable.
As Paul says, ConcurrentHashMaps provide thread safe maps with additional useful methods for atomic updates.