kaoziun
kaoziun

Reputation: 53

Thread-safety simple

If I have a list of Components in a multithreading environnment and if I do any operation on this list except add (I use the keyword synchronized on the list in this case) and get (the method called by a component is thread-safe), is that thread-safe?

public class Test {

   private final ArrayList<Component> myContainer = new ArrayList<Component>();

   public void add(Component){
      synchronized(myContainer){
          myContainer.add(Component)
      }
   }

   public void useComponents()
   {
      for(Component c : myContainer)
           c.use(); // method thread-safe
   }

   // no other operations on myContainer
}

Upvotes: 0

Views: 50

Answers (2)

Marco13
Marco13

Reputation: 54639

In the current form, it is not thread-safe: The useComponents method could be executed by one thread. At the same time, another thread could call add, and thus modify the collection while it is being iterated over. (This modification could happen between two calls to c.use(), so the fact that the use() method is thread safe would not help you here).

Strictly speaking, this is not even restricted to multithreading: If the c.use() internally called test.add(someOtherComponent) (even if it was done in the same thread!) this would throw a ConcurrentModificiationException, because again, the collection is modified while being iterated over.

Thread safety (without safety agains concurrent modifications) could be achieved by simply wrapping the iteration into a synchronized block:

public void useComponents()
{
   synchronized (myContainer) 
   {
       for(Component c : myContainer)
           c.use(); // method thread-safe
   }

}

However, this would still leave the possibility of a ConcurrentModificationException. Most likely the c.use() call will not (and should not) modify the collection that the component is contained in (otherwise, one could question the design in general).

If you wanted to allow the c.use() call to modify the collection, you could replace the collection with a CopyOnWriteArrayList:

private final List<Component> myContainer = 
    new CopyOnWriteArrayList<Component>();

and then you could even remove the synchroniziation completely. But you should be aware of the implications: The contents of the list will be copied during each modification (hence the name...). This is usually used in cases where you have a small collection that is frequently iterated over, but which is rarely modified. (Listeners in all forms are a classic example here).

Upvotes: 1

Sergey
Sergey

Reputation: 3721

It looks ok, except that I am not sure about iterator behavior in useComponents() if you'll simultaneously add elements to the list.

Did you consider using CopyOnWriteArrayList instead?

Upvotes: 0

Related Questions