Search code examples
javasynchronizationhashsetsynchronized

Is modifying an object (e.g. a HashSet) in a synchronized block equivalent to making it a synchronized object?


I understand that you can get a thread-safe HashSet with

HashSet<String> mySynchronizedHashSet = Collections.synchronizedSet(new HashSet<String>());

But what about taking using a traditional HashSet and enclosing it with a synchronized block every time you want to modify it?

synchronized(myRegularHashSet) {
    myRegularHashSet.add(new String());
}

Aside from the disadvantage of having remember to add the synchronized keyword every time you want to modify the set safely, are the two techniques equivalent? Do I ever need to use both? How might they compare in terms of performance? Supposing that the HashSet is at risk of concurrent modification only under circumstances that are known and rare, could you save time by synchronizing it only when necessary?

EDIT 1: Just found this previous answer which answers some of my questions (though not the ones about performance).

EDIT 2: To address one of my own questions "(Do I ever need to use both?"), I will quote from the Javadoc, "It is imperative that the user manually synchronize on the returned collection when traversing it via Iterator, Spliterator or Stream." I assume this to mean that the synchronized block always necessary when using, for example, an Iterator, but that it's not necessary to use a synchronized block and a synchronized object.


Solution

  • As long as you only access the HashSet from inside a synchronized method or block (and synchronized on the same object!), it's equivalent. I tend to prefer the 'synchronized' keyword rather than the special form of the set (but then, I drive a stick-shift).

    There's little gain in most cases in trying to be smart about when you need to sync, because sync'ing when there's no concurrency is generally going to be overhead that's lost in the noise. Besides, sync also affects visibility of changes.