Что такое Vector и чем он отличается от ArrayList?
Lock Coarsening — оптимизация JVM, которая объединяет несколько последовательных synchronized-блоков в один, чтобы снизить накладные расходы на блокировку.
🟢 Junior Level
Vector — устаревшая версия ArrayList, которая была в Java с самого начала.
Главная разница:
| Vector | ArrayList | |
|---|---|---|
| Синхронизация | ✅ Все методы синхронизированы | ❌ Нет |
| Скорость | Медленнее | Быстрее |
| Ресайз | × 2 | × 1.5 |
| Когда использовать | Только в legacy-коде, новый код — ArrayList или CopyOnWriteArrayList |
Пример:
// ❌ Не используйте Vector
Vector<String> v = new Vector<>(); // Медленный!
// ✅ Используйте ArrayList
List<String> list = new ArrayList<>();
Почему Vector медленный:
- Каждый метод =
synchronized - Даже если работаете в одном потоке!
🟡 Middle Level
Технические отличия
// Vector:
public synchronized boolean add(E e) { // ← synchronized!
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
// ArrayList:
public boolean add(E e) { // ← Нет synchronized!
modCount++;
add(e, elementData, size);
return true;
}
Резайз
Vector: capacity × 2
10 → 20 → 40 → 80
→ Быстро растёт, больше wasted memory
ArrayList: capacity × 1.5
10 → 15 → 22 → 33
→ Экономнее, меньше фрагментация
Почему синхронизация Vector НЕ помогает
// ❌ Vector НЕ потокобезопасен для составных операций!
if (!vector.contains(obj)) { // Проверка
vector.add(obj); // ← Другой поток может вклиниться!
}
Это называется race condition **«check-then-act»**: проверка (`contains`) и действие (`add`) — две отдельные операции, между которыми другой поток может вмешаться.
// Всё равно нужен внешний synchronized:
synchronized (vector) {
if (!vector.contains(obj)) {
vector.add(obj);
}
}
Альтернативы
// Без синхронизации:
ArrayList<String> list = new ArrayList<>();
// С синхронизацией (много чтений):
List<String> list = new CopyOnWriteArrayList<>();
// С синхронизацией (универсальный):
List<String> list = Collections.synchronizedList(new ArrayList<>());
// Для очередей:
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
Как выбрать:
- Один поток → ArrayList
- Много потоков, много чтений → CopyOnWriteArrayList
- Много потоков, смешанная нагрузка → Collections.synchronizedList
- Много потоков, очередь → ConcurrentLinkedQueue
🔴 Senior Level
Lock Contention
100 потоков вызывают vector.get(0):
→ Все ждут один монитор
→ Сериализация → 0 параллелизма!
ArrayList:
→ 100 потоков читают одновременно
→ Lock-free reading
JIT Lock Coarsening
Lock Coarsening — оптимизация JVM, которая объединяет несколько последовательных synchronized-блоков в один, чтобы снизить накладные расходы на блокировку.
JVM пытается оптимизировать:
vector.get(0);
vector.get(1);
vector.get(2);
→ Lock Coarsening: один lock на все три
→ Но это маскирует проблему, не решает!
LSP Violation: Stack наследуется от Vector
LSP (Liskov Substitution Principle) — принцип ООП: подкласс должен быть заменяем базовым классом без изменения корректности программы. Stack нарушает это, потому что добавляет методы, несовместимые с семантикой стека.
// Stack extends Vector!
Stack<String> stack = new Stack<>();
stack.push("A");
stack.add(0, "B"); // ← Нарушает семантику стека!
// → Stack может делать всё, что Vector
// → Это нарушение Liskov Substitution Principle
Enumeration vs Iterator
// Vector имеет Enumeration (устаревший)
Enumeration<String> e = vector.elements();
while (e.hasMoreElements()) {
e.nextElement(); // Не fail-fast!
}
// Iterator (современный)
Iterator<String> it = vector.iterator();
// → Fail-fast, как у ArrayList
Production Experience
Реальный сценарий: Vector убил throughput
- Приложение: 1000 RPS, Vector для логов
- Lock contention: 80% времени на synchronized
- Решение: ArrayList
- Результат: +400% throughput
Best Practices
- НЕ используйте Vector — это legacy
- ArrayList — по умолчанию
- CopyOnWriteArrayList — для thread-safe
- Collections.synchronizedList — универсальный
- ConcurrentLinkedQueue — для очередей
- Stack → ArrayDeque — для стеков
- Enumeration → Iterator — современный
Резюме для Senior
- Vector = legacy, synchronized, медленный
- ArrayList = быстрее, без синхронизации
- Синхронизация Vector не даёт реальной thread-safety
- Lock Contention убивает параллелизм
- Ресайз × 2 → больше фрагментация
- Stack extends Vector = LSP violation
- CopyOnWriteArrayList = правильная thread-safe альтернатива
- Никогда не используйте Vector в новом коде
🎯 Шпаргалка для интервью
Обязательно знать:
- Vector = legacy, все методы synchronized → медленный даже в одном потоке
- Резайз: Vector × 2 (больше фрагментация) vs ArrayList × 1.5 (экономнее)
- Синхронизация Vector НЕ даёт реальной thread-safety для составных операций (race condition «check-then-act»)
- Lock Contention: 100 потоков вызывают vector.get() → сериализация → 0 параллелизма
- Stack extends Vector = LSP violation — можно вызвать get(index), нарушая LIFO-семантику
- Enumeration (Vector) устарел → используйте Iterator (fail-fast)
- Альтернативы: ArrayList (один поток), CopyOnWriteArrayList (много чтений), Collections.synchronizedList (универсальный)
- Реальный кейс: замена Vector → ArrayList дала +400% throughput
Частые уточняющие вопросы:
- Почему synchronized в Vector не гарантирует thread-safety? — Составные операции (check-then-act) всё равно требуют внешнего synchronized
- Что такое LSP violation в контексте Stack? — Stack наследуется от Vector, можно вызвать add(0,e) — нарушает LIFO
- Когда JIT Lock Coarsening маскирует проблему? — Объединяет последовательные synchronized-блоки, но это не решает lock contention
- Чем CopyOnWriteArrayList лучше Vector? — Копия при записи, lock-free чтение, лучше для сценариев «много чтений, мало записей»
Красные флаги (НЕ говорить):
- ❌ “Vector — потокобезопасная замена ArrayList” — synchronized не даёт реальной thread-safety для составных операций
- ❌ “Vector × 2 ресайз лучше чем ArrayList × 1.5” — наоборот, больше фрагментация и wasted memory
- ❌ “Используйте Stack как стек” — Stack extends Vector, используйте ArrayDeque
- ❌ “Enumeration лучше Iterator” — Enumeration устарел, не fail-fast
Связанные темы:
- [[Что такое Stack]]
- [[В чём разница между ArrayList и LinkedList]]
- [[Какие основные интерфейсы Collection Framework]]
- [[Что такое Deque]]