I disagree, William. (Or should that be "I think Willims is wrong"?)

The legacy collection classes are
bêtes noires for Peter den Haan and myself for several reasons - this is the biggest one: Often the synchronization provided by those classes is not at the right level to really ensure
thread safety, and so using those classes gives people a false sense of security. For example:
Although Vector is "thread safe", nothing prevents another thread from accessing the Vector
in between invocations of size() and get(). So it's possible that an element could be removed just before it's accessed, leading to an ArrayIndexOutOfBoundsException. Or other strange things could happen, like elements being accessed twice, or skipped entirely, because elements were added or removed while the iteration was going on. The same problems exist if you use an Enumeration or Iterator. The usual way to solve this is to explicitly synchronize on the Vector (or some other appropriate object) somewhere
outside the iteration loop. Once you have to do this, there's really no point in also having synchronization on the size() and get() methods - it's just making the JVM do a little more work, with no benefit.
In general, I recommend using explicit synchronized blocks to put in synchronization as needed - and think carefully about where this should be. Taking the shortcut of using "thread-safe" classes often just encourages carelessness, IMO. It's true that there are some cases where using a Vector may turn out to be slightly faster than using explicit synchronization blocks (or alternately, using Collections.synchronizedList() and the like). But it's pretty rare that this sort of optimization makes a notable difference, and usually it's much more important to ensure your "thread safety" is really correct. Plus by choosing judiciously exactly where to synchronize, you can often get better performance gains than by simply using Vector
et al.