I suggest the following solution:
- For
Map
collections, replace them withConcurrentHashMap
. Thismap
has iterators tolerant to collection changes, and locking of it is striped based on keyshashCode()
. - For
Set
collections, use sets created by factoryCollections.newSetFromMap()
withConcurrentHashMap
instance passed as an argument. This will provide you withset
with same thread-safety-related properties as formap
I mentioned above. For
List
collections, first consider whether you really needList
. If yes, consider usingCopyOnWriteArrayList
or wrapping original list withList list = Collections.synchronizedList(new ArrayList()); //or maybe LinkedList, but this is not related to the question.
Please be advised that iterators returned by this wrapped list are not thread-safe and may throw ConcurrentModificationException
.
Now, you may encounter problem - Set
returned by the factory, cannot have same values in it. If this is a problem for you, try use some Guava Multiset
. Further information about it can be found here.
Ok, we finished with the collections. Now, let's consider its updates on the example of ConcurrentHashMap
.
Implementation of this structure provides you so-called eventual visibility guarantees. That means that each iterator represents some collection state - maybe not the last one, but the state is guaranteed to be valid at some moment of time, maybe in the past. Usually that is enough for most cases.
That means that to parallelize handling of some activities, you can pass the reference to this collection to your Thread
or Runnable
which modifies it, and to some other Thread
or Runnable
that reads it, and you should be fine.
Note that throughput for the List
I mentioned above will be lower, because this collection is exclusively accessed due to synchronized
blocks added by that wrapper.