Skip to main content
Documents
Share
LinkedIn
Facebook
Twitter
Copy
Java keywordsIntroduction To JavaJava File HandlingJava Language BasicsJava ArraysJava Object-Oriented Programming

synchronized Keyword in Java

The synchronized keyword in Java controls access to shared resources among multiple threads. It guarantees that only one thread can executed a synchronized block or method at a time, preventing thread interference and ensuring memory consistency.

Usage

The synchronized keyword can be applied to methods or blocks within methods. When a method or block is declared as synchronized, a lock is obtained on the specified object, and other threads are blocked from accessing the synchronized code until the lock is released.

Syntax

Synchronized Method

public synchronized void synchronizedMethod() {
    // method code
}

Synchronized Block

public void method() {
    synchronized (object) {
        // synchronized code
    }
}
  • object: The object on which to synchronize. This is typically the current instance (this) or a specific object.

Examples

Example 1: Synchronized Method

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        // Create multiple threads to increment the counter
        Thread t1 = new Thread(() -> counter.increment());
        Thread t2 = new Thread(() -> counter.increment());

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + counter.getCount());
    }
}

In this example, the increment method is synchronized, ensuring that only one thread can increment the counter at a time, preventing race conditions.

Example 2: Synchronized Block

public class SynchronizedBlockExample {
    private final Object lock = new Object();
    private int count = 0;

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedBlockExample example = new SynchronizedBlockExample();

        // Create multiple threads to increment the counter
        Thread t1 = new Thread(() -> example.increment());
        Thread t2 = new Thread(() -> example.increment());

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

This example uses a synchronized block to control access to the count variable. The lock object ensures that only one thread can execute the synchronized block at a time.

Tips and Best Practices

  • Minimize Synchronized Code: Keep synchronized blocks as short as possible to reduce contention and improve performance.
  • Use Final Objects: When using synchronized blocks, use final objects as locks to ensure consistency.
  • Avoid Nested Synchronization: Nested synchronized blocks can lead to deadlocks. Avoid them or use them with caution.
  • Use Concurrent Collections: For complex synchronization, consider using concurrent collections from the java.util.concurrent package, such as ConcurrentHashMap, which provide built-in synchronization.
  • Volatile Keyword: For variables that are accessed by multiple threads but do not require complex synchronization, consider using the volatile keyword to ensure visibility.
private volatile boolean flag;
  • Thread Safety: Always ensure that shared resources are properly synchronized to maintain thread safety and avoid data corruption.
  • Synchronized Static Methods: Synchronize static methods to enforce synchronized access at the class level, ensuring only one thread can execute the static method across all instances.
public static synchronized void staticMethod() {
    // method code
}
  • Reentrancy: Java's intrinsic locks are reentrant, meaning if a thread holds a lock, it can acquire it again without deadlocking itself.