What does 'synchronized' mean?

Learn what does 'synchronized' mean? with practical examples, diagrams, and best practices. Covers java, multithreading, keyword development techniques with visual explanations.

Understanding 'synchronized' in Java: A Deep Dive into Thread Safety

Hero image for What does 'synchronized' mean?

Explore the 'synchronized' keyword in Java, its role in multithreading, and how it prevents race conditions and ensures data consistency in concurrent applications.

In the world of concurrent programming, managing shared resources among multiple threads is a critical challenge. Without proper control, threads can interfere with each other, leading to data corruption, inconsistent states, and unpredictable program behavior. Java's synchronized keyword is a fundamental mechanism designed to address these issues, providing a way to enforce thread safety and ensure data integrity.

What is 'synchronized'?

The synchronized keyword in Java is a powerful tool for controlling access to shared resources by multiple threads. It ensures that only one thread can execute a synchronized block or method at any given time, effectively preventing race conditions and maintaining data consistency. When a thread enters a synchronized block or method, it acquires a lock on the associated object or class. Other threads attempting to enter the same synchronized block or method will be blocked until the lock is released by the first thread.

sequenceDiagram
    participant ThreadA
    participant ThreadB
    participant SharedObject

    ThreadA->>SharedObject: Attempt to acquire lock
    activate SharedObject
    SharedObject-->>ThreadA: Lock acquired
    ThreadA->>SharedObject: Execute synchronized code
    ThreadA->>SharedObject: Release lock
    deactivate SharedObject

    ThreadB->>SharedObject: Attempt to acquire lock
    Note over ThreadB,SharedObject: ThreadB is blocked until lock is released
    activate SharedObject
    SharedObject-->>ThreadB: Lock acquired
    ThreadB->>SharedObject: Execute synchronized code
    ThreadB->>SharedObject: Release lock
    deactivate SharedObject

Sequence diagram illustrating how 'synchronized' manages thread access to a shared object.

How 'synchronized' Works: Locks and Monitors

At its core, synchronized relies on the concept of intrinsic locks, also known as monitor locks. Every Java object has an intrinsic lock associated with it. When a thread invokes a synchronized method or enters a synchronized block, it attempts to acquire the lock for the object that owns the method or block. If the lock is available, the thread acquires it and proceeds. If the lock is already held by another thread, the current thread enters a waiting state until the lock is released. Once the thread exits the synchronized block or method (either normally or due to an exception), the lock is automatically released.

Applying 'synchronized': Methods vs. Blocks

The synchronized keyword can be applied in two main ways: to methods or to blocks of code. Each approach has its own use cases and implications for concurrency control.

public class Counter {
    private int count = 0;

    // Synchronized method: locks the 'Counter' object
    public synchronized void increment() {
        count++;
    }

    // Synchronized block: locks 'this' (the current Counter instance)
    public void decrement() {
        synchronized (this) {
            count--;
        }
    }

    // Synchronized static method: locks the 'Counter.class' object
    public static synchronized void staticIncrement() {
        // ... operates on static fields ...
    }

    // Synchronized block on a specific object
    private final Object lock = new Object();
    public void safeOperation() {
        synchronized (lock) {
            // ... thread-safe operations ...
        }
    }

    public int getCount() {
        return count;
    }
}

When a non-static method is declared synchronized, the lock is acquired on the instance of the object (this). For static synchronized methods, the lock is acquired on the Class object itself (e.g., Counter.class). A synchronized block, on the other hand, allows you to specify any object as the lock. This is particularly useful when you need to protect only a portion of a method or when you want to use a different lock object than this to avoid deadlocks or allow more concurrency for unrelated operations.