What is thread synchronization and why is it important?

Thread synchronization is a mechanism that controls access to shared resources when multiple threads are running concurrently. Its primary purpose is to ensure that only one thread can execute a critical section of code at a time, preventing data inconsistency and maintaining thread safety.

Key Points: • Synchronization prevents race conditions when multiple threads access shared data. • It ensures data consistency and predictable application behavior. • Java provides synchronization using synchronized methods, synchronized blocks, locks, and concurrent utilities. • Only one thread can access a synchronized resource at a given time. • Synchronization is essential in multi-threaded applications that share mutable data.

Why Is Synchronization Important?

Consider a shared bank account balance:

Initial Balance:

1000

Thread 1:

Deposit 500

Thread 2:

Withdraw 200

Without synchronization:

• Both threads may read the same balance simultaneously. • One update may overwrite the other. • The final balance may become incorrect.

This issue is known as a Race Condition.

How Synchronization Solves the Problem

Synchronization ensures:

1. One thread enters the critical section. 2. Other threads wait until the lock is released. 3. Shared data remains consistent.

Example:

Without Synchronization

Thread 1 → Read Balance = 1000

Thread 2 → Read Balance = 1000

Thread 1 → Update Balance = 1500

Thread 2 → Update Balance = 800

Incorrect Result:

800

With Synchronization

Thread 1 → Complete Update

Thread 2 → Perform Update

Correct Result:

1300

Code Example:

class Counter {

    private int count = 0;

    public synchronized void increment() {

        count++;
    }

    public int getCount() {

        return count;
    }
}

public class Demo {

    public static void main(String[] args)
            throws InterruptedException {

        Counter counter = new Counter();

        Runnable task = () -> {

            for (int i = 0; i < 1000; i++) {

                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

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

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

        System.out.println(
                counter.getCount());
    }
}

Output:

2000

Without synchronization, the result may be less than 2000 due to race conditions.

Ways to Achieve Synchronization in Java

1. Synchronized Method

public synchronized void update() {

    // Critical section
}

Locks the entire method.

2. Synchronized Block

public void update() {

    synchronized (this) {

        // Critical section
    }
}

Locks only the required code block.

3. ReentrantLock

Provides advanced locking features.

Example:

lock.lock();

try {

    // Critical section

} finally {

    lock.unlock();
}

4. Concurrent Collections

Examples:

• ConcurrentHashMap • CopyOnWriteArrayList

Designed for thread-safe operations.

Real-World Example

Online Ticket Booking System

Multiple users try to book the last available seat.

Without Synchronization:

• Multiple bookings may succeed. • Data becomes inconsistent.

With Synchronization:

• Only one user books the seat. • Remaining users receive an unavailable message.

Benefits of Synchronization

• Prevents race conditions • Maintains data consistency • Ensures thread safety • Protects shared resources • Improves application reliability

Potential Drawbacks

• Increased waiting time for threads • Reduced parallelism • Excessive synchronization can impact performance

Therefore, synchronize only critical sections of code.

Interview Tip: A concise interview answer is:

"Thread synchronization is the process of controlling access to shared resources in a multi-threaded environment. It ensures that only one thread can execute a critical section at a time, preventing race conditions and maintaining data consistency. In Java, synchronization can be achieved using synchronized methods, synchronized blocks, locks, and concurrent collections."