Java HashTable size() followed by values() safe in thread? - java

I have the following executing sequentially in the one thread:
int size = hashTable.size();
foreach.... in ... hasTable.values()
do something
My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?

No, HashTable is thread-safe on method level (multiple threads can call any method at any time) but there is no cross-method synchronization. It's possible that between your two instructions other thread adds/removes or even clears the hashtable.
If you need to keep such invariant, make a defensive copy (doesn't have to be thread safe) and do size()/loop on that copy:
Map<K, V> map = null;
synchronized(hashTable) {
map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
//...
}
Here for-each is safe and it's guaranteed to run size-times. Also as noted in comments, you can just synchronize on hashTable:
synchronized(hashTable) {
int size = hashTable.size();
for(V v: hashTable.values()) {
//...
}
}
However this solution means that only one thread at a time can perform the loop (this can become a bottleneck if your loop takes some time to complete). With defensive copy each thread has its own copy and several threads can loop at the same time. On the other hand this solution is better if hashTable is very big (expensive to copy) but the iteration is very fast.

If another thread will modify the hashTable during the execution of the foreach than your code will throw a ConcurrentModificationException.

Your example is not thread safe, but it can be easily made thread safe like so:
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}

Java HashTable size() followed by values() safe in thread?
So it's not values() method call that is unsafe. It's that you open an iterator on values() which is backed by the HashTable. It is the iterator which throws an exception if modifications are made to the table while it is iterating.
My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?
As mentioned, the HashTable will throw an exception if it is modified while you are iterating across it.
HashTable has all but been deprecated. If you are looking for a modern, concurrent version of HashMap then you should be using ConcurrentHashMap which was added in Java 5. ConcurrentHashMap properly handles the case where modifications happen in the background as you iterate across it without extra synchronization or copying:
ConcurrentHashMap<...> map = new ConcurrentHashMap<...>();
int size = map.size();
for (... value : map.values()) {
// may be called more or less than size if other threads add or delete
...
}

Related

ArrayList vs Vector performance in single-threaded application

I was just looking for the answer for the question why ArrayList is faster than Vector and i found ArrayList is faster as it is not synchronized.
so my doubt is:
If ArrayList is not synchronized why would we use it in multithreaded environment and compare it with Vector.
If we are in a single threaded environment then how the performance of the Vector decreases as there is no Synchronization going on as we are dealing with a single thread.
Why should we compare the performance considering the above points ?
Please guide me :)
a) Methods using ArrayList in a multithreaded program may be synchronized.
class X {
List l = new ArrayList();
synchronized void add(Object e) {
l.add(e);
}
...
b) We can use ArrayList without exposing it to other threads, this is when ArrayList is referenced only from local variables
void x() {
List l = new ArrayList(); // no other thread except current can access l
...
Even in a single threaded environment entering a synchronized method takes a lock, this is where we lose performance
public synchronized boolean add(E e) { // current thread will take a lock here
modCount++;
...
You can use ArrayList in a multithread environment if the list is not shared between threads.
If the list is shared between threads you can synchronize the access to that list.
Otherwise you can use Collections.synchronizedList() to get a List that can be used thread safely.
Vector is an old implementation of a synchronized List that is no longer used because the internal implementation basically synchronize every method. Generally you want to synchronize a sequence of operations. Otherwyse you can throw a ConcurrentModificationException when iterating the list another thread modify it. In addition synchronize every method is not good from a performance point of view.
In addition also in a single thread environment accessing a synchronized method needs to perform some operations, so also in a single thread application Vector is not a good solution.
Just because a component is single threaded doesn't mean that it cannot be used in a thread safe context. Your application may have it's own locking in which case additional locking is redundant work.
Conversely, just because a component is thread safe, it doesn't mean that you cannot use it in an unsafe manner. Typically thread safety extends to a single operation. E.g. if you take an Iterator and call next() on a collection this is two operations and they are no longer thread safe when used in combination. You still have to use locking for Vector. Another simple example is
private Vector<Integer> vec =
vec.add(1);
int n = vec.remove(vec.size());
assert n == 1;
This is atleast three operations however the number of things which can go wrong are much more than you might suppose. This is why you end up doing your own locking and why the locking inside Vector might be redundant, even unwanted.
For you own interest;
vec can change at any point t another Vector or null
vec.add(2) can happen between any operation, changing the size and the last element.
vec.remove() can happen between any operation.
vec.add(null) can happen between any operation resulting in a possible NullPointerException
The vec can /* change */ in these places.
private Vector<Integer> vec =
vec.add(1); /* change*/
int n = vec.remove(vec.size() /* change*/);
assert n == 1;
In short, assuming that just because you used a thread safe collection your code is now thread safe is a big assumption.
A common pattern which breaks is
for(int n : vec) {
// do something.
}
Look harmless enough except
for(Iterator iter = vec.iterator(); /* change */ vec.hasNext(); ) {
/* change */ int n = vec.next();
I have marked with /* change */ where another thread could change the collection meaning this loop can get a ConcurrentModificationException (but might not)
there is no Synchronization
The JVM doesn't know there is no need for synchronization and so it still has to do something. It has an optimisation to reduce the cost of uncontended locks, but it still has to do work.
You need to understand the basic concept to know answer for your above questions...
When you say array list is not syncronized and vector is, we mean that the methods in those classes (like add(), get(), remove() etc...) are synchronized in vector class and not in array list class. These methods will act upon tha data being stored .
So, the data saved in vector class cannot be edited / read parallely as add, get, remove metods are synchornized and the same in array list can be done parallely as these methods in array list are not synchronized...
This parallel activity makes array list fast and vector slow... This behavior remains same though you use them in either multithreaded (or) single threaded enviornment...
Hope this answers your question...

ConcurrentModificationException using Iterator

I'm using an iterator to loop over a collection as follows:
Iterator<Entity> entityItr = entityList.iterator();
while (entityItr.hasNext())
{
Entity curr = entityItr.next();
for (Component c : curr.getComponents())
{
if (c instanceof PlayerControlled)
{
((PlayerControlled) c).pollKeyboard();
}
}
}
However on the following line I get a ConcurrentModificationException
Entity curr = entityItr.next();
Why is this happening when I'm not altering anything?
Many thanks
Edit - stack trace:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at cw.systems.Input.checkInputs(Input.java:31)
at cw.systems.Input.begin(Input.java:21)
at cw.misc.Game.render(Game.java:73)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
You must be modifying the list either:
inside your iterator in the pollKeyboard method, without using the add or remove methods on the iterator; or
in another thread
Therefore your exception is the expected behaviour. From the docs, if you have a single thread iterating the list:
if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException
and if multiple threads uses the list at one time:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally
Solution:
If only one thread accesses the list, make sure you use the entityItr.remove or add methods to modify the list.
For the multi-threaded case you can use Collections.synchronizedList if you do not have a locking object available.
First store a single central reference to your list as:
entityList = Collections.synchronizedList(theOriginalArrayList);
And then access it (with all readers and writers) as:
synchronized (entityList) {
// Readers might do:
itr = entityList.iterator();
while (i.hasNext())
... do stuff ...
}
There are other ways to sync multi-threaded access, including copying the list to an array (inside a sync block) and iterating it for reading, or using a ReadWrite lock. They all depend on your exact requirement.
It looks that there is another thread using the same collection and modifing it when this code is iterating over the collection.
ConcurrentModificationException
You can use navite java concurrent collestions instead. They are thread safe. However it's a good habbit to create immutable collections - they are thread safe and enforce you to design reliable code.

Wrapped implementation of a map

What's the point of wrapping the map with Collections.synchronizedCollection(map), if then you have to synchronize the code while iterating?
Collection<Type> c = Collections.synchronizedCollection(myCollection);
synchronized(c) {
for (Type e : c)
foo(e); }
After having wrapped it, should not be thread safe?
What's the point of wrapping the map with Collections.synchronizedCollection(map), if then you have to synchronize the code while iterating?
To make individual operations thread-safe. (Personally I think it's a bad idea in general, but that's a different matter. It's not pointless, just limited in usefulness.)
After having wrapped it, should not be thread safe?
For any individual operation, yes. But iteration involves many steps - and while each of those individual steps will be synchronized, the collection can be modified between steps, invalidating the iterator. Don't forget that your loop is expanded to something like:
for (Iterator<Type> iterator = c.iterator(); iterator.hasNext(); ) {
Type e = iterator.next();
...
}
If you need iteration to be thread-safe, you should use one of the collections in java.util.concurrent... while noting the caveats about what is and isn't guaranteed if the collection is modified during iteration.
After wrapping it, each individual method is thread safe, but iteration involves calling methods repeatedly (iterator, then next and hasNext on the returned Iterator) and there's no synchronization between those methods. This is why you need to synchronize your iteration.
You also need to use a synchronized collection (rather than just synchronizing around your iteration code) because otherwise the methods that add or remove items would not synchronize and therefore could make modifications while you were iterating even if you used a synchronized block.
Adding to #jonskeet's #jule's answers, you should consider using ConcurrentHashMap (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html) which does not require locking around iteration.

Creating a ConcurrentHashMap that supports "snapshots"

I'm attempting to create a ConcurrentHashMap that supports "snapshots" in order to provide consistent iterators, and am wondering if there's a more efficient way to do this. The problem is that if two iterators are created at the same time then they need to read the same values, and the definition of the concurrent hash map's weakly consistent iterators does not guarantee this to be the case. I'd also like to avoid locks if possible: there are several thousand values in the map and processing each item takes several dozen milliseconds, and I don't want to have to block writers during this time as this could result in writers blocking for a minute or longer.
What I have so far:
The ConcurrentHashMap's keys are Strings, and its values are instances of ConcurrentSkipListMap<Long, T>
When an element is added to the hashmap with putIfAbsent, then a new skiplist is allocated, and the object is added via skipList.put(System.nanoTime(), t).
To query the map, I use map.get(key).lastEntry().getValue() to return the most recent value. To query a snapshot (e.g. with an iterator), I use map.get(key).lowerEntry(iteratorTimestamp).getValue(), where iteratorTimestamp is the result of System.nanoTime() called when the iterator was initialized.
If an object is deleted, I use map.get(key).put(timestamp, SnapShotMap.DELETED), where DELETED is a static final object.
Questions:
Is there a library that already implements this? Or barring that, is there a data structure that would be more appropriate than the ConcurrentHashMap and the ConcurrentSkipListMap? My keys are comparable, so maybe some sort of concurrent tree would better support snapshots than a concurrent hash table.
How do I prevent this thing from continually growing? I can delete all of the skip list entries with keys less than X (except for the last key in the map) after all iterators that were initialized on or before X have completed, but I don't know of a good way to determine when this has happened: I can flag that an iterator has completed when its hasNext method returns false, but not all iterators are necessarily going to run to completion; I can keep a WeakReference to an iterator so that I can detect when it's been garbage collected, but I can't think of a good way to detect this other than by using a thread that iterates through the collection of weak references and then sleeps for several minutes - ideally the thread would block on the WeakReference and be notified when the wrapped reference is GC'd, but I don't think this is an option.
ConcurrentSkipListMap<Long, WeakReference<Iterator>> iteratorMap;
while(true) {
long latestGC = 0;
for(Map.Entry<Long, WeakReference<Iterator>> entry : iteratorMap.entrySet()) {
if(entry.getValue().get() == null) {
iteratorMap.remove(entry.getKey());
latestGC = entry.getKey();
} else break;
}
// remove ConcurrentHashMap entries with timestamps less than `latestGC`
Thread.sleep(300000); // five minutes
}
Edit: To clear up some confusion in the answers and comments, I'm currently passing weakly consistent iterators to code written by another division in the company, and they have asked me to increase the strength of the iterators' consistency. They are already aware of the fact that it is infeasible for me to make 100% consistent iterators, they just want a best effort on my part. They care more about throughput than iterator consistency, so coarse-grained locks are not an option.
What is your actual use case that requires a special implementation? From the Javadoc of ConcurrentHashMap (emphasis added):
Retrievals reflect the results of the most recently completed update operations holding upon their onset. ... 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.
So the regular ConcurrentHashMap.values().iterator() will give you a "consistent" iterator, but only for one-time use by a single thread. If you need to use the same "snapshot" multiple times and/or by multiple threads, I suggest making a copy of the map.
EDIT: With the new information and the insistence for a "strongly consistent" iterator, I offer this solution. Please note that the use of a ReadWriteLock has the following implications:
Writes will be serialized (only one writer at a time) so write performance may be impacted.
Concurrent reads are allowed as long as there is no write in progress, so read performance impact should be minimal.
Active readers block writers but only as long as it takes to retrieve the reference to the current "snapshot". Once a thread has the snapshot, it no longer blocks writers no matter how long it takes to process the information in the snapshot.
Readers are blocked while any write is active; once the write finishes then all readers will have access to the new snapshot until a new write replaces it.
Consistency is achieved by serializing the writes and making a copy of the current values on each and every write. Readers that hold a reference to a "stale" snapshot can continue to use the old snapshot without worrying about modification, and the garbage collector will reclaim old snapshots as soon as no one is using it any more. It is assumed that there is no requirement for a reader to request a snapshot from an earlier point in time.
Because snapshots are potentially shared among multiple concurrent threads, the snapshots are read-only and cannot be modified. This restriction also applies to the remove() method of any Iterator instances created from the snapshot.
import java.util.*;
import java.util.concurrent.locks.*;
public class StackOverflow16600019 <K, V> {
private final ReadWriteLock locks = new ReentrantReadWriteLock();
private final HashMap<K,V> map = new HashMap<>();
private Collection<V> valueSnapshot = Collections.emptyList();
public V put(K key, V value) {
locks.writeLock().lock();
try {
V oldValue = map.put(key, value);
updateSnapshot();
return oldValue;
} finally {
locks.writeLock().unlock();
}
}
public V remove(K key) {
locks.writeLock().lock();
try {
V removed = map.remove(key);
updateSnapshot();
return removed;
} finally {
locks.writeLock().unlock();
}
}
public Collection<V> values() {
locks.readLock().lock();
try {
return valueSnapshot; // read-only!
} finally {
locks.readLock().unlock();
}
}
/** Callers MUST hold the WRITE LOCK. */
private void updateSnapshot() {
valueSnapshot = Collections.unmodifiableCollection(
new ArrayList<V>(map.values())); // copy
}
}
I've found that the ctrie is the ideal solution - it's a concurrent hash array mapped trie with constant time snapshots
Solution1) What about just synchronizing on the puts, and on the iteration. That should give you a consistent snapshot.
Solution2) Start iterating and make a boolean to say so, then override the puts, putAll so that they go into a queue, when the iteration is finished simply make those puts with the changed values.

Java synchronized block vs. Collections.synchronizedMap

Is the following code set up to correctly synchronize the calls on synchronizedMap?
public class MyClass {
private static Map<String, List<String>> synchronizedMap = Collections.synchronizedMap(new HashMap<String, List<String>>());
public void doWork(String key) {
List<String> values = null;
while ((values = synchronizedMap.remove(key)) != null) {
//do something with values
}
}
public static void addToMap(String key, String value) {
synchronized (synchronizedMap) {
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
}
}
}
From my understanding, I need the synchronized block in addToMap() to prevent another thread from calling remove() or containsKey() before I get through the call to put() but I do not need a synchronized block in doWork() because another thread cannot enter the synchronized block in addToMap() before remove() returns because I created the Map originally with Collections.synchronizedMap(). Is that correct? Is there a better way to do this?
Collections.synchronizedMap() guarantees that each atomic operation you want to run on the map will be synchronized.
Running two (or more) operations on the map however, must be synchronized in a block.
So yes - you are synchronizing correctly.
If you are using JDK 6 then you might want to check out ConcurrentHashMap
Note the putIfAbsent method in that class.
There is the potential for a subtle bug in your code.
[UPDATE: Since he's using map.remove() this description isn't totally valid. I missed that fact the first time thru. :( Thanks to the question's author for pointing that out. I'm leaving the rest as is, but changed the lead statement to say there is potentially a bug.]
In doWork() you get the List value from the Map in a thread-safe way. Afterward, however, you are accessing that list in an unsafe matter. For instance, one thread may be using the list in doWork() while another thread invokes synchronizedMap.get(key).add(value) in addToMap(). Those two access are not synchronized. The rule of thumb is that a collection's thread-safe guarantees don't extend to the keys or values they store.
You could fix this by inserting a synchronized list into the map like
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, Collections.synchronizedList(valuesList)); // sync'd list
Alternatively you could synchronize on the map while you access the list in doWork():
public void doWork(String key) {
List<String> values = null;
while ((values = synchronizedMap.remove(key)) != null) {
synchronized (synchronizedMap) {
//do something with values
}
}
}
The last option will limit concurrency a bit, but is somewhat clearer IMO.
Also, a quick note about ConcurrentHashMap. This is a really useful class, but is not always an appropriate replacement for synchronized HashMaps. Quoting from its Javadocs,
This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details.
In other words, putIfAbsent() is great for atomic inserts but does not guarantee other parts of the map won't change during that call; it guarantees only atomicity. In your sample program, you are relying on the synchronization details of (a synchronized) HashMap for things other than put()s.
Last thing. :) This great quote from Java Concurrency in Practice always helps me in designing an debugging multi-threaded programs.
For each mutable state variable that may be accessed by more than one thread, all accesses to that variable must be performed with the same lock held.
Yes, you are synchronizing correctly. I will explain this in more detail.
You must synchronize two or more method calls on the synchronizedMap object only in a case you have to rely on results of previous method call(s) in the subsequent method call in the sequence of method calls on the synchronizedMap object.
Let’s take a look at this code:
synchronized (synchronizedMap) {
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
}
In this code
synchronizedMap.get(key).add(value);
and
synchronizedMap.put(key, valuesList);
method calls are relied on the result of the previous
synchronizedMap.containsKey(key)
method call.
If the sequence of method calls were not synchronized the result might be wrong.
For example thread 1 is executing the method addToMap() and thread 2 is executing the method doWork()
The sequence of method calls on the synchronizedMap object might be as follows:
Thread 1 has executed the method
synchronizedMap.containsKey(key)
and the result is "true".
After that operating system has switched execution control to thread 2 and it has executed
synchronizedMap.remove(key)
After that execution control has been switched back to the thread 1 and it has executed for example
synchronizedMap.get(key).add(value);
believing the synchronizedMap object contains the key and NullPointerException will be thrown because synchronizedMap.get(key)
will return null.
If the sequence of method calls on the synchronizedMap object is not dependent on the results of each other then you don't need to synchronize the sequence.
For example you don't need to synchronize this sequence:
synchronizedMap.put(key1, valuesList1);
synchronizedMap.put(key2, valuesList2);
Here
synchronizedMap.put(key2, valuesList2);
method call does not rely on the results of the previous
synchronizedMap.put(key1, valuesList1);
method call (it does not care if some thread has interfered in between the two method calls and for example has removed the key1).
That looks correct to me. If I were to change anything, I would stop using the Collections.synchronizedMap() and synchronize everything the same way, just to make it clearer.
Also, I'd replace
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
with
List<String> valuesList = synchronziedMap.get(key);
if (valuesList == null)
{
valuesList = new ArrayList<String>();
synchronziedMap.put(key, valuesList);
}
valuesList.add(value);
The way you have synchronized is correct. But there is a catch
Synchronized wrapper provided by Collection framework ensures that the method calls I.e add/get/contains will run mutually exclusive.
However in real world you would generally query the map before putting in the value. Hence you would need to do two operations and hence a synchronized block is needed. So the way you have used it is correct. However.
You could have used a concurrent implementation of Map available in Collection framework. 'ConcurrentHashMap' benefit is
a. It has a API 'putIfAbsent' which would do the same stuff but in a more efficient manner.
b. Its Efficient: dThe CocurrentMap just locks keys hence its not blocking the whole map's world. Where as you have blocked keys as well as values.
c. You could have passed the reference of your map object somewhere else in your codebase where you/other dev in your tean may end up using it incorrectly. I.e he may just all add() or get() without locking on the map's object. Hence his call won't run mutually exclusive to your sync block. But using a concurrent implementation gives you a peace of mind that it
can never be used/implemented incorrectly.
Check out Google Collections' Multimap, e.g. page 28 of this presentation.
If you can't use that library for some reason, consider using ConcurrentHashMap instead of SynchronizedHashMap; it has a nifty putIfAbsent(K,V) method with which you can atomically add the element list if it's not already there. Also, consider using CopyOnWriteArrayList for the map values if your usage patterns warrant doing so.

Categories