Synchronized Blocks & Methods

About

In Java, synchronization ensures that multiple threads do not interfere with each other while accessing shared resources. The synchronized keyword is used to prevent race conditions, ensure atomicity, and maintain data consistency in multi-threaded applications.

Why is Synchronization Needed?

When multiple threads operate on shared data, race conditions can occur. This leads to inconsistent, corrupted, or unpredictable results. Synchronization ensures that only one thread at a time can access a critical section.

Example Without Synchronization (Race Condition)

class SharedResource {
    private int count = 0;

    void increment() { // Not synchronized
        count++;
    }

    int getCount() {
        return count;
    }
}

public class RaceConditionExample {
    public static void main(String[] args) throws InterruptedException {
        SharedResource resource = new SharedResource();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                resource.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                resource.increment();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Final Count: " + resource.getCount()); // Expected: 2000, but may be incorrect due to race condition
    }
}

Output (Inconsistent Results)

Here, multiple threads modify count simultaneously, leading to data corruption.

Synchronized Methods

A synchronized method ensures that only one thread at a time can execute the method on an instance of the class.

  • When a thread enters a synchronized method, it acquires an intrinsic lock (also known as monitor lock) on the object.

  • If another thread attempts to call any other synchronized method on the same object, it will be blocked until the first thread releases the lock.

  • This prevents race conditions but introduces performance overhead due to blocking.

Syntax

Example of Synchronized Method

Output (Always Correct)

How It Works?

  • The method is synchronized using synchronized keyword.

  • Java uses an intrinsic lock (monitor) on the instance (this).

  • If one thread enters the method, other threads must wait until it exits.

When to Use?

  • When the entire method needs to be protected.

  • When a class method modifies instance variables shared between threads.

  • When a method is small and does not require fine-grained locking.

Synchronized Blocks

Instead of locking an entire method, a synchronized block locks only a specific critical section inside a method.

  • This allows other non-critical code to execute without blocking.

  • Instead of locking the entire object (this), it can use a custom lock object, allowing more flexibility.

Syntax

Example 1

Example 2

Synchronized block locking entire object (also called intrinsic locking on this)

  • synchronized (this) locks the entire object (SharedPrinter in this case).

  • Only one thread at a time can enter the synchronized block for that object.

  • If another thread tries to enter the synchronized block, it has to wait until the lock is released.

  • This ensures thread-safe access to critical sections that depend on the shared object state.

How It Works?

  • The lock is applied only on the necessary code block.

  • Other parts of the method can execute without blocking.

  • This increases efficiency compared to synchronizing the whole method.

When to Use?

  • When only a part of the method needs protection.

  • When performance is a concern, and unnecessary locking is avoided.

  • When multiple locks are required for different data elements.

Class-Level Synchronization (Static Methods)

Class-level synchronization ensures that only one thread at a time can execute a synchronized static method, across all instances of the class.

  • The lock is on the Class object (Class<T>) instead of an instance.

  • Even if multiple objects of the class exist, they share the same class-level lock.

Example

When to Use?

  • When modifying static variables shared across multiple instances.

Class-Level Lock vs. Instance-Level Lock

Aspect

Instance-Level Lock

Class-Level Lock

Scope

Applied to a single object

Applied to the entire class

Effect

Only one thread per object can enter

Only one thread across all instances can enter

Use Case

When dealing with instance-specific data

When dealing with shared static data

Comparison Table

Feature

Synchronized Method

Synchronized Block

Class-Level Synchronization

Lock Type

Intrinsic lock on this (object)

Lock on a specific section

Lock on Class<T>

Performance

Low (entire method is locked)

High (only necessary section locked)

Moderate (static method locks entire class)

Flexibility

Low (locks entire method)

High (can use custom lock objects)

Medium (locks entire static method)

Use Case

When entire method needs synchronization

When part of a method needs synchronization

When static shared data needs synchronization

Last updated