I lately had to play around a lot with collections in multi-threaded environments and learned several new stuff that I’d like to share:
Vector vs. ArrayList
Where is the difference between both? When should you use ArrayList and when is the time to use Vector?
This is a very common question and often leads to huge discussions.
For me, the following two points are sufficient in order to decide when to use what:
- Vector is threadsafe. ArrayList is not.
That means that you can have two threads accessing (and manipulating) a vector without having to worry about mutual exclusion. - ArrayList is a little faster than Vector but not threadsafe.
Lists in multi-threaded environments
Now, if you have multiple threads in your application which both access collections at the same time, you might run into issues because this is simply not allowed. Think of the list as a piece of cake. Only one guy can eat it.
As mentioned above, Vector is threadsafe, so in theory you could assume that it’s perfectly alright if you only use Vectors through the whole application. That’s wrong. See the example below, which will cause a ConcurrentModificationException.
So, if you have thread 1 doing this:
List<Person> persons = new Vector<Person>(); fillList(persons); for (Person person : persons){ if (person.getName().equals("timo")){ doSomething(person); persons.remove(person); break; } }
.. and thread 2 does the same thing at the same time, you’ll most likely face a ConcurrentModificationException.
That’s because
- The “
for (Person person : persons)
” syntax creates an implicit iterator which is not thread safe. - You cannot iterate over a collection and modify it at the same time.
Solution: Use the synchronized keyword and iterate over a copy but modify the original
List<Person> persons = new Vector<Person>(); fillList(persons); synchronized(persons){ List<Person> copy = new Vector<Person>(persons); for (Person person : copy){ if (person.getName().equals("timo")){ doSomething(person); persons.remove(person); break; } } }
Wrapping the for loop into a synchronized block will synchronize access between multiple threads.
This must be done in all threads which could possibly manipulate the vector. Adding the synchronized keyword in just thread 1 will not work unless thread 2 also uses this keyword.
Also, the above code creates a copy of the original list and iterates over it. Note that the call of persons.remove(person)
happens on the orignal list.
If you’re creating a synchronized block with “persons”, isn’t that negating the advantage of using a vector? Couldn’t you achieve the same solution by wrapping an ArrayList in a synchronized block?
I think the advantage would be that you wouldn’t have to wrap ALL vector manipulations with a synchronized block, but only the ones that use an iterator.