The classes in the Java Collections Framework are not thread-safe, that is, their contents may be corrupted if they are accessed and updated concurrently by multiple threads. You can protect the data in a collection by locking the collection or by using synchronized collections.
The Collections class provides six static methods for wrapping a collection into a synchronized version, as shown in Figure 24.27. The collections created using these methods are called synchronization wrappers .
Invoking synchronizedCollection(Collection c) returns a new Collection object, in which all the methods that access and update the original collection c are synchronized. These methods are implemented using the synchronized keyword . For example, the add method is implemented like this:
public boolean add(E o) { synchronized ( this ) { return c.add(o); } }
Synchronized collections can be safely accessed and modified by multiple threads concurrently.
Note
The methods in java.util.Vector , java.util.Stack , and java.util.Hashtable are already synchronized. These are old classes introduced in JDK 1.0. In JDK 1.5, you should use java.util.ArrayList to replace Vector , java.util.LinkedList to replace Stack , and java.util.Map to replace java.util.Hashtable . If synchronization is needed, use a synchronization wrapper. |
The synchronization wrapper classes are thread-safe, but the iterator is fail-fast . This means that if you are using an iterator to traverse a collection while the underlying collection is being modified by another thread, then the iterator will immediately fail by throwing java.util.ConcurrentModificationException , which is a subclass of RuntimeException . To avoid this error, you need to create a synchronized collection object and acquire a lock on the object when traversing it. For example, suppose you want to traverse a set, you have to write the code like this:
Set hashSet = Collections.synchronizedSet( new HashSet()); synchronized (hashSet) { // Must synchronize it Iterator iterator = hashSet.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
Failure to do so may result in nondeterministic behavior, such as ConcurrentModificationException .