Що таке 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]]