← Back to Home

Thread Synchronization

Thread synchronization in Java is the mechanism used to control access to shared resources in a multi-threaded environment. It ensures data consistency, thread safety, and predictable behavior when multiple threads execute concurrently. This is a very high-frequency interview topic.

Why Thread Synchronization Is Needed

In multithreading, multiple threads may access and modify shared data simultaneously, leading to:

  • Race conditions
  • Inconsistent results
  • Data corruption

Example Problem (Race Condition)

class Counter {
    int count = 0;
    void increment() {
        count++;
    }
}
          

Multiple threads calling increment() → incorrect count

What Is Synchronization?

  • Ensures only one thread accesses a critical section at a time
  • Achieved using locks (monitors)
  • Prevents race conditions

Synchronization in Java (Ways)

  1. Synchronized Method
  2. Synchronized Block
  3. Static Synchronization
  4. Inter-thread Communication (wait, notify) (preview)

1️⃣ Synchronized Method

Locks the object (instance).

class Counter {
    int count = 0;
    synchronized void increment() {
        count++;
    }
}
          
  • ✔ Only one thread can execute this method per object
  • ✔ Lock = this

2️⃣ Synchronized Block (Preferred)

Locks specific code, not entire method.

class Counter {
    int count = 0;
    void increment() {
        synchronized (this) {
            count++;
        }
    }
}
          
  • ✔ Better performance
  • ✔ Fine-grained control

3️⃣ Static Synchronization

Locks the class-level object.

class Counter {
    static int count = 0;
    static synchronized void increment() {
        count++;
    }
}
          
  • ✔ Lock = Counter.class
  • ✔ Shared across all objects

Object Lock vs Class Lock (Interview Favorite)

Type Lock Used
Instance method Object lock (this)
Synchronized block Specified object
Static method Class lock (ClassName.class)

What Is a Monitor Lock?

  • Every Java object has an intrinsic lock (monitor)
  • synchronized acquires this lock
  • Released when thread exits synchronized area

Synchronization Example (Correct Output)

class Counter {
    int count = 0;
    synchronized void increment() {
        count++;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Counter c = new Counter();
        Thread t1 = new Thread(() -> {
            for(int i=0;i<1000;i++) c.increment();
        });
        Thread t2 = new Thread(() -> {
            for(int i=0;i<1000;i++) c.increment();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(c.count); // 2000
    }
}
          

Synchronization and Performance

  • Synchronization adds overhead
  • Excessive synchronization reduces performance
  • Use minimal critical sections

Synchronization Does NOT Solve

  • Deadlocks
  • Thread starvation
  • Livelocks
  • (Handled separately)

Alternatives to synchronized (Preview)

  • java.util.concurrent.locks.Lock
  • ReentrantLock
  • Atomic classes (AtomicInteger)

Common Beginner Mistakes

  • Synchronizing entire methods unnecessarily
  • Synchronizing on wrong object
  • Forgetting static vs instance lock difference
  • Assuming synchronization fixes all concurrency issues

Interview-Ready Answers

Short Answer

Thread synchronization ensures that only one thread accesses shared resources at a time.

Detailed Answer

In Java, thread synchronization is achieved using the synchronized keyword to control access to critical sections of code. It prevents race conditions and ensures data consistency by allowing only one thread to hold a lock on an object or class at a time.

Key Takeaway

Synchronization protects shared data, not threads. Use it carefully and minimally to balance correctness and performance.