What is Vector and how does it differ from ArrayList?
Lock Coarsening — JVM optimization that merges several sequential synchronized blocks into one to reduce lock overhead.
🟢 Junior Level
Vector — legacy version of ArrayList that has been in Java since the beginning.
Key difference:
| Vector | ArrayList | |
|---|---|---|
| Synchronization | ✅ All methods synchronized | ❌ No |
| Speed | Slower | Faster |
| Resize | × 2 | × 1.5 |
| When to use | Only in legacy code, new code — ArrayList or CopyOnWriteArrayList |
Example:
// ❌ Don't use Vector
Vector<String> v = new Vector<>(); // Slow!
// ✅ Use ArrayList
List<String> list = new ArrayList<>();
Why Vector is slow:
- Every method =
synchronized - Even when working in single thread!
🟡 Middle Level
Technical differences
// Vector:
public synchronized boolean add(E e) { // ← synchronized!
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
// ArrayList:
public boolean add(E e) { // ← No synchronized!
modCount++;
add(e, elementData, size);
return true;
}
Resize
Vector: capacity × 2
10 → 20 → 40 → 80
→ Grows fast, more wasted memory
ArrayList: capacity × 1.5
10 → 15 → 22 → 33
→ More economical, less fragmentation
Why Vector synchronization DOESN’T help
// ❌ Vector NOT thread-safe for compound operations!
if (!vector.contains(obj)) { // Check
vector.add(obj); // ← Another thread can interject!
}
This is called **"check-then-act"** race condition: check (`contains`) and action (`add`) — two separate operations where another thread can interfere.
// Still need external synchronized:
synchronized (vector) {
if (!vector.contains(obj)) {
vector.add(obj);
}
}
Alternatives
// No synchronization:
ArrayList<String> list = new ArrayList<>();
// With synchronization (many reads):
List<String> list = new CopyOnWriteArrayList<>();
// With synchronization (universal):
List<String> list = Collections.synchronizedList(new ArrayList<>());
// For queues:
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
How to choose:
- Single thread → ArrayList
- Multi-thread, many reads → CopyOnWriteArrayList
- Multi-thread, mixed load → Collections.synchronizedList
- Multi-thread, queue → ConcurrentLinkedQueue
🔴 Senior Level
Lock Contention
100 threads call vector.get(0):
→ All wait for single monitor
→ Serialization → 0 parallelism!
ArrayList:
→ 100 threads read simultaneously
→ Lock-free reading
JIT Lock Coarsening
Lock Coarsening — JVM optimization that merges several sequential synchronized blocks into one to reduce lock overhead.
JVM tries to optimize:
vector.get(0);
vector.get(1);
vector.get(2);
→ Lock Coarsening: one lock for all three
→ But this masks the problem, doesn't solve it!
LSP Violation: Stack extends Vector
LSP (Liskov Substitution Principle) — OOP principle: subclass must be substitutable by base class without breaking correctness. Stack violates this by adding methods incompatible with stack semantics.
// Stack extends Vector!
Stack<String> stack = new Stack<>();
stack.push("A");
stack.add(0, "B"); // ← Breaks stack semantics!
// → Stack can do everything Vector can
// → Violation of Liskov Substitution Principle
Enumeration vs Iterator
// Vector has Enumeration (legacy)
Enumeration<String> e = vector.elements();
while (e.hasMoreElements()) {
e.nextElement(); // Not fail-fast!
}
// Iterator (modern)
Iterator<String> it = vector.iterator();
// → Fail-fast, like ArrayList
Production Experience
Real case: Vector killed throughput
- App: 1000 RPS, Vector for logs
- Lock contention: 80% time on synchronized
- Solution: ArrayList
- Result: +400% throughput
Best Practices
- DO NOT use Vector — it’s legacy
- ArrayList — by default
- CopyOnWriteArrayList — for thread-safe
- Collections.synchronizedList — universal
- ConcurrentLinkedQueue — for queues
- Stack → ArrayDeque — for stacks
- Enumeration → Iterator — modern
Summary for Senior
- Vector = legacy, synchronized, slow
- ArrayList = faster, no synchronization
- Vector synchronization doesn’t give real thread-safety
- Lock Contention kills parallelism
- Resize × 2 → more fragmentation
- Stack extends Vector = LSP violation
- CopyOnWriteArrayList = proper thread-safe alternative
- NEVER use Vector in new code
🎯 Interview Cheat Sheet
Must know:
- Vector = legacy, all methods synchronized → slow even in single thread
- Resize: Vector × 2 (more fragmentation) vs ArrayList × 1.5 (more economical)
- Vector synchronization DOESN’T give real thread-safety for compound operations (race condition “check-then-act”)
- Lock Contention: 100 threads call vector.get() → serialization → 0 parallelism
- Stack extends Vector = LSP violation — can call get(index), breaking LIFO semantics
- Enumeration (Vector) is legacy → use Iterator (fail-fast)
- Alternatives: ArrayList (single thread), CopyOnWriteArrayList (many reads), Collections.synchronizedList (universal)
- Real case: Vector → ArrayList replacement gave +400% throughput
Common follow-up questions:
- Why doesn’t synchronized in Vector guarantee thread-safety? — Compound operations (check-then-act) still need external synchronized
- What is LSP violation in Stack context? — Stack extends Vector, can call add(0,e) — breaks LIFO
- When does JIT Lock Coarsening mask the problem? — Merges sequential synchronized blocks, but doesn’t solve lock contention
- How is CopyOnWriteArrayList better than Vector? — Copy on write, lock-free reading, better for “many reads, few writes” scenarios
Red flags (NOT to say):
- ❌ “Vector — thread-safe replacement for ArrayList” — synchronized doesn’t give real thread-safety for compound operations
- ❌ “Vector × 2 resize better than ArrayList × 1.5” — opposite, more fragmentation and wasted memory
- ❌ “Use Stack as stack” — Stack extends Vector, use ArrayDeque
- ❌ “Enumeration better than Iterator” — Enumeration is legacy, not fail-fast
Related topics:
- [[What is Stack]]
- [[What is the difference between ArrayList and LinkedList]]
- [[What are the main Collection Framework interfaces]]
- [[What is Deque]]