views:

170

answers:

3

I'm using Collections.synchronizedCollection in Java to protect a Set that I know is getting accessed concurrently by many threads. The Java API warns:

" It is imperative that the user manually synchronize on the returned collection when iterating over it:

Collection c = Collections.synchronizedCollection(myCollection);
     ...
  synchronized(c) {
      Iterator i = c.iterator(); // Must be in the synchronized block
      while (i.hasNext())
         foo(i.next());
  }

"

If I use c.contains(obj), is that thread-safe? Internally, obviously, this is iterating over the Collection and seeing if any of the objects in it are equal to obj. My instinct is to assume that this is probably synchronized (it would seem to be a major failing if not), but given previous pains with synchronization, it seems wise to double-check, and a Google search for answers on this hasn't turned up anything.

+1  A: 

It's safe, because contains itself is synchronized.

daveb
Thanks: out of curiosity, how do you confirm that? Is it just sort of common knowledge that these synchronized classes are done so by adding synchronized to every method? I tried to go through the .class file for Collections but couldn't really take anything out of it.
DivineWolfwood
@DivineWolfwood To double check, I have the JDK sources, so I clicked through and took a look.
daveb
@DivineWolfwood: Apart from examining the source-code, the only way to determine that is from the JavaDoc. This is why it's so important to document the concurrent behavior and requirements of classes -- something that's still a work in progress.
Steve Emmerson
+5  A: 

In itself, a call to contains is safe.

The problem is that one often tests whether a collection contains an element then does something to the collection based on the result.

Most likely, the test and the action should be treated as a single, atomic operation. In that case, a lock on the collection should be obtained, and both operations should be performed in the synchronized block.

erickson
That's a good point; I hadn't considered that I was adding a value to it if it wasn't in there. Under that circumstance, it seems obviously necessary that I'll have to manually synchronize.
DivineWolfwood
And in that case, why not just add it? What is the underlying set implementation doing? For example, for a HashSet a contains and then an add is doing double the work of just add. In your case, regardless of the Set implementation add would be an atomic operation with respect to synchronization and your add() code would need to handle duplicates anyway (even if itself is just checking contains()) in order to properly meet the contract of add().
PSpeed
@PSpeed: Great suggestion. It saves me from having to do the synchronization, because I'm adding it anyway.
DivineWolfwood
A: 

Collections.synchronizedCollection() will return a thread safe collection which means any single method call is thread safe by itself. It depends what you want do. If you want to call couple of methods, java cannot make it thread safe together.

fastcodejava