Это сделано «поточно-ориентированным» благодаря всем синхронизируемым методам (через ключевое слово synchronized), см. Исходный код OpenJDK .
Что делает синхронизированное ключевое слово, так это то, что оно предотвращает выполнение несколькими синхронизированными методами одновременно несколькими потоками. Он использует внутреннюю блокировку, которую поток должен получить при входе в эти методы, и этот поток освобождает, когда покидает метод.
Обратите внимание, что это не очень помогает, потому что, хотя и предотвращает противоречивое внутреннее состояние вектора, это никоим образом не гарантирует уровень согласованности на более высоком уровне (полезный уровень для приложения).
Рассмотрите этот пример, который показывает, что вам все еще нужно использовать синхронизацию в коде вашего приложения (чтобы вы могли с тем же успехом использовать несинхронизированный ArrayList):
// BROKEN CODE, needs external synchronization
// only add an element if the vector is empty
if(vector.isEmpty())
vector.add(anElement);