synchronized Keyword
The synchronized keyword in Java is used to control concurrent access to shared resources. It ensures that only one thread at a time executes a critical section of code protected by the same lock, thereby preventing race conditions and ensuring data consistency. This is a very high-frequency interview topic in Java multithreading.
What Does synchronized Do?
- Acquires a monitor lock before executing code
- Allows mutual exclusion
- Releases the lock automatically when execution exits
- Ensures visibility of shared data (happens-before guarantee)
Monitor Lock (Intrinsic Lock)
- Every Java object has a monitor (intrinsic) lock
- synchronized uses this lock internally
- A thread must own the lock to enter synchronized code
Ways to Use synchronized
1️⃣ Synchronized Instance Method
Locks the current object (this).
class Counter {
int count = 0;
synchronized void increment() {
count++;
}
}
✔ Only one thread per object can execute this method at a time
2️⃣ Synchronized Block (Recommended)
Locks a specific object and limits the critical section.
class Counter {
int count = 0;
void increment() {
synchronized (this) {
count++;
}
}
}
✔ Better performance
✔ Fine-grained locking
3️⃣ Synchronized Static Method
Locks the class-level lock.
class Counter {
static int count = 0;
static synchronized void increment() {
count++;
}
}
✔ Lock used: Counter.class
✔ Shared across all instances
Object Lock vs Class Lock (Interview Favorite)
| Usage | Lock Acquired |
|---|---|
| Instance synchronized method | this |
| Synchronized block | Specified object |
| Static synchronized method | ClassName.class |
How synchronized Works (Execution Flow)
- Thread requests lock
- If lock available → thread enters block/method
- Other threads are BLOCKED
- Thread exits synchronized code
- Lock is released automatically
Visibility Guarantee (Important)
- Changes made inside synchronized block
- Are visible to other threads after lock release
✔ Solves visibility issues
✔ Prevents stale reads
synchronized and Thread States
- Waiting for lock → BLOCKED
- Inside synchronized code → RUNNABLE
What synchronized Does NOT Do
- Does NOT guarantee fairness
- Does NOT prevent deadlocks
- Does NOT improve performance
- Does NOT replace good design
Common Mistakes
- Synchronizing entire methods unnecessarily
- Synchronizing on wrong object
- Using this as lock in public APIs
- Overusing synchronized causing performance issues
Best Practices (Production-Grade)
- Prefer synchronized blocks over methods
- Keep synchronized code minimal
- Avoid synchronizing on mutable/public objects
- Use private final lock objects if needed
private final Object lock = new Object();
synchronized (lock) {
// critical section
}
synchronized vs volatile (Quick Contrast)
| Aspect | synchronized | volatile |
|---|---|---|
| Mutual exclusion | ✔ Yes | ❌ No |
| Visibility | ✔ Yes | ✔ Yes |
| Atomicity | ✔ Yes | ❌ No |
| Performance | Slower | Faster |
Advanced synchronized Scenarios
1. synchronized Method (Instance Lock)
class Counter {
int count = 0;
synchronized void increment() {
count++;
}
}
Explanation
- Lock acquired on current object (this).
- Only one thread per object can execute this method.
2. Non-synchronized Method Runs in Parallel
class Demo {
synchronized void syncMethod() {
System.out.println("Synchronized");
}
void normalMethod() {
System.out.println("Not synchronized");
}
}
Explanation
- normalMethod() can run parallel with syncMethod().
3. synchronized Block (Preferred)
class Counter {
int count = 0;
void increment() {
synchronized (this) {
count++;
}
}
}
Why preferred
- Locks only critical section.
- Better performance than full method sync.
4. Synchronizing on a Custom Lock Object
class Counter {
int count = 0;
private final Object lock = new Object();
void increment() {
synchronized (lock) {
count++;
}
}
}
Best practice
- Avoid locking this.
- Safer for large classes.
5. Two Threads, Same Object → Blocked
class Demo {
synchronized void work() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
Demo d = new Demo();
new Thread(d::work).start();
new Thread(d::work).start();
}
}
Explanation
- Same object → same lock → one thread at a time.
6. Two Objects → No Blocking
class Demo {
synchronized void work() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
new Thread(() -> new Demo().work()).start();
new Thread(() -> new Demo().work()).start();
}
}
Explanation
- Different objects → different locks.
7. static synchronized Method (Class Lock)
class Printer {
static synchronized void print() {
System.out.println(Thread.currentThread().getName());
}
}
Explanation
- Lock acquired on Class object.
- Blocks all threads across all instances.
8. Instance Lock vs Class Lock Together
class Test {
synchronized void instanceMethod() {
System.out.println("Instance lock");
}
static synchronized void staticMethod() {
System.out.println("Class lock");
}
}
Key Point
- Instance lock ≠ Class lock.
- Can run in parallel.
9. synchronized(this) vs synchronized(ClassName.class)
synchronized (this) {
// object-level lock
}
synchronized (Test.class) {
// class-level lock
}
10. synchronized with Runnable
class Task implements Runnable {
int count = 0;
public synchronized void run() {
count++;
System.out.println(count);
}
}
Explanation
- Synchronization applies on Runnable object.
11. synchronized and sleep() (Important Trap)
class Demo {
synchronized void work() throws Exception {
Thread.sleep(1000);
}
}
Key Point
- sleep() ❌ does NOT release lock.
12. synchronized and wait()
class Demo {
synchronized void work() throws Exception {
wait();
}
}
Key Point
- wait() ✅ releases lock.
13. Illegal Monitor State (Common Interview Trap)
class Demo {
void work() throws Exception {
// wait(); // ❌ IllegalMonitorStateException
}
}
Rule
- wait() / notify() must be inside synchronized.
14. notify() vs notifyAll()
class Demo {
synchronized void resumeOne() {
notify();
}
synchronized void resumeAll() {
notifyAll();
}
}
15. Over-Synchronization (Bad Practice)
class Demo {
synchronized void hugeMethod() {
// long running logic
}
}
Problem
- Reduces concurrency.
- Use smaller synchronized blocks.
16. synchronized Is Reentrant
class Demo {
synchronized void m1() {
m2();
}
synchronized void m2() {
System.out.println("Reentrant lock");
}
}
Explanation
- Same thread can re-enter lock.
17. synchronized with Multiple Methods
class Demo {
synchronized void m1() {}
synchronized void m2() {}
}
Explanation
- Same object → same lock.
- Only one method runs at a time.
18. ❌ Synchronizing on New Object (Useless)
synchronized (new Object()) {
// No real synchronization
}
Why wrong
- New object every time → no shared lock.
19. synchronized vs AtomicInteger
// synchronized
synchronized void increment() { count++; }
// atomic
AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
Interview Note
- Atomic → faster, lock-free.
20. Interview Summary – synchronized
synchronized
Key Points
- Provides mutual exclusion.
- Uses intrinsic locks.
- Object lock vs Class lock.
- Reentrant.
- Can cause deadlock if misused.
Interview-Ready Answers
Short Answer
synchronized ensures that only one thread accesses a critical section at a time.
Detailed Answer
In Java, the synchronized keyword is used to acquire an intrinsic lock on an object or class before executing critical code. It prevents race conditions, ensures data consistency, and provides memory visibility guarantees by enforcing happens-before relationships.
Key Takeaway
synchronized protects shared data, not threads. Use it sparingly and precisely to achieve correctness without sacrificing performance.