Classes like Vector, Hashtable and Wrappers created by Collections.synchronizedXxx achieves thread safety by synchronizing every public method so that only one thread at a time can access the collection state.
Problems
a. Malfunction in compound actions
Synchronized collections are technically thread-safe but sometimes, additional client side locking needed to guard operations like :
1. Iteration
2. Navigation
3. Condition : put-if-absent
Example
public static Object getLast(Vector list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
public static void deleteLast(Vector list) {
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
If thread A calls getLast on a Vector with 10 elements, thread B calls deleteLast on the same Vector, and the operations are interleaved so getLast throws ArrayIndexOutOfBoundsException.
Solution
Client side locking keeping the lock of collection using synchronized block in both above methods. Although, it will have some additional scalability cost.
Example
public static Object getLast(Vector list) {
synchronized (list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
}
b. Fail-Fast : cannot deal with Concurrent modification
The iterators returned by the synchronized collections cannot deal with concurrent modification as they are fail-fast means they throw the unchecked ConcurrentModificationException when they detect the collection has changed since iteration began.
The methods like containsAll, removeAll, retainAll and constructors taking collections as argument may indirectly iterate the collection and may throw ConcurrentModificationException.
Solution #1
During iteration, clone the collection and iterate the copy instead so that no other thread can modify it during iteration, eliminating the possibility of ConcurrentModificationException.
Although, cloning has a performance cost.
Solution #2
Use locking everywhere a shared collection might be iterated.
No comments:
Post a Comment
Note: only a member of this blog may post a comment.