Synchronization
Thread synchronization in Java — synchronized blocks, locks, volatile, atomic classes, and concurrent collections for thread-safe code.
Last reviewed: January 2025
🔍 What Is It?
Synchronization Mechanisms:
1. synchronized keyword
- →Intrinsic lock (monitor) on any object
- →synchronized method: lock is the object (this) or class
- →synchronized block: lock is the specified object
- →Reentrant: a thread can re-acquire a lock it already holds
2. ReentrantLock (java.util.concurrent.locks)
- →Explicit lock with more features than synchronized
- →tryLock() — non-blocking attempt
- →lockInterruptibly() — can be interrupted while waiting
- →Condition variables — fine-grained wait/notify
- →Fairness option — prevents starvation
3. ReadWriteLock
- →ReentrantReadWriteLock: multiple readers OR one writer
- →Ideal for read-heavy, write-rare scenarios
4. volatile
- →Guarantees visibility (changes visible to all threads)
- →Does NOT guarantee atomicity (count++ is still a race)
- →Use for simple flags and status variables
5. Atomic classes (java.util.concurrent.atomic)
- →AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference
- →Lock-free using CAS (Compare-And-Swap) hardware instructions
- →Faster than synchronized for simple operations
6. Concurrent Collections
- →ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue
- →Thread-safe collections without external synchronization
🎯 Why Do We Need It?
Without synchronization, concurrent access to shared mutable state causes race conditions — the result depends on the unpredictable timing of thread scheduling. Race conditions cause data corruption, incorrect calculations, and intermittent bugs that are nearly impossible to reproduce in testing.
🏗️ What Happens in Real Projects?
In enterprise code:
- →ConcurrentHashMap for shared caches (most common)
- →AtomicLong for thread-safe counters and ID generation
- →ReentrantReadWriteLock for caches with rare updates
- →synchronized for simple critical sections
- →volatile for stop flags in background threads
⚙️ How It Works
CAS (Compare-And-Swap):
Atomic classes use CAS hardware instructions:
- Read current value
- Compute new value
- Atomically: if current value == expected, set to new value; else retry
This is lock-free — no blocking, no deadlock possible.
Memory Model:
Java Memory Model (JMM) defines when changes to memory made by one thread are visible to another. synchronized and volatile both establish happens-before relationships that guarantee visibility.
💻 Example
Synchronization Patterns — Choosing the right synchronization mechanism for each use case.
🤔 Common Confusions
❓ Does synchronized on a method lock the entire class?
No. synchronized on an instance method locks the object instance (this). Different instances can execute synchronized methods simultaneously. Only synchronized static methods lock the Class object. Two threads calling synchronized methods on the same instance block each other; two threads on different instances do not.
❓ Is ConcurrentHashMap fully thread-safe for all operations?
Individual operations (get, put, remove) are thread-safe. Compound operations (check-then-act) are NOT automatically atomic. Example: if (!map.containsKey(k)) map.put(k, v) is a race condition. Use computeIfAbsent() or putIfAbsent() for atomic compound operations.
🚨 Common Production Issues
Lock not released in exception path — if an exception occurs between lock() and unlock(), the lock is never released. Always use try-finally: lock.lock(); try { ... } finally { lock.unlock(); }
Deadlock in production — very hard to detect until it happens. Use jstack to identify BLOCKED threads. Prevention: consistent lock ordering, tryLock with timeout.
Synchronized on wrong object — synchronized(new Object()) creates a new lock each time, providing no synchronization. Always synchronize on the same object.
✅ Best Practices
Use ConcurrentHashMap instead of synchronizing a HashMap.
Use AtomicInteger/AtomicLong instead of synchronized for counters.
Always release locks in finally blocks.
Minimize the scope of synchronized blocks — hold locks as briefly as possible.
Use consistent lock ordering to prevent deadlocks.
Prefer high-level concurrent utilities over synchronized whenever possible.
🏛️ Architect's Note
The best synchronization is no synchronization. Design for immutability (immutable objects are thread-safe by definition), use message passing instead of shared state (actor model, queues), and confine mutable state to a single thread. When you must share mutable state, use the highest-level abstraction available: ConcurrentHashMap over synchronized HashMap, AtomicLong over synchronized counter.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Threads
Java threads — creating and managing threads, thread lifecycle, and the concurrency problems every enterprise developer must understand.
Executor Framework
The Executor framework — thread pools, ExecutorService types, and how to configure them for production workloads.