Fundamentals 11 min read

Mastering Java’s synchronized: How Object and Class Locks Control Threads

This article explains the purpose and usage of Java’s synchronized keyword, covering object locks, method locks, synchronized blocks, and class locks, along with detailed code examples that demonstrate how threads acquire and release locks to ensure data consistency in multithreaded environments.

Architecture & Thinking
Architecture & Thinking
Architecture & Thinking
Mastering Java’s synchronized: How Object and Class Locks Control Threads

1 Introduction

This article introduces the key keywords involved in Java thread management, focusing on the synchronized keyword.

2 synchronized

2.1 Concept

In Java, the synchronized keyword is used to achieve thread synchronization, ensuring data consistency and safety in a multithreaded environment.

2.2 Function

It can be applied to methods or code blocks to guarantee that only one thread executes the method or block at a time.

When a thread holds an object's lock, other threads cannot access the synchronized method or block of that object until the lock is released.

2.3 Points to Note

A lock can be held by only one thread at a time; other threads must wait.

Each instance has its own lock (this); different instances do not interfere. Exception: the lock object is *.class or when synchronized decorates a static method, all objects share the same lock.

A method synchronized with synchronized releases its lock whether it completes normally or throws an exception.

2.4 Object Lock

Object locks apply to object instances; each instance has its own monitor lock. When a thread holds an object's lock, other threads cannot simultaneously access the synchronized code block or method protected by synchronized .

2.4.1 Method Lock

A method lock is achieved by declaring the method with the synchronized keyword. When a thread calls a method marked with synchronized , it automatically acquires the lock of the object instance and releases it after the method finishes.

Code Example:

<code>public class SynchronizedMethodLock {
    public synchronized void synMethod() {
        System.out.println("Thread " + Thread.currentThread().getName() + " is executing synMethod.");
        // Simulate method execution
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SynchronizedMethodLock obj = new SynchronizedMethodLock();
        Thread t1 = new Thread(obj::synMethod, "T1");
        Thread t2 = new Thread(obj::synMethod, "T2");
        t1.start();
        t2.start();
    }
}
</code>

In this example, the synMethod is synchronized, so thread T1 acquires the lock first; thread T2 must wait until T1 finishes and releases the lock.

2.4.2 Synchronized Block Lock

A synchronized block lock is created by using synchronized(object) inside a code block, allowing finer‑grained control over the synchronization scope.

Code Example:

<code>public class SynchronizedBlockLock {
    private final Object lock = new Object();

    public void synBlock() {
        System.out.println("Thread " + Thread.currentThread().getName() + " is trying to enter synBlock.");
        synchronized (lock) {
            System.out.println("Thread " + Thread.currentThread().getName() + " has entered synBlock.");
            // Simulate block execution
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " is leaving synBlock.");
        }
    }

    public static void main(String[] args) {
        SynchronizedBlockLock obj = new SynchronizedBlockLock();
        Thread t1 = new Thread(obj::synBlock, "T1");
        Thread t2 = new Thread(obj::synBlock, "T2");
        t1.start();
        t2.start();
    }
}
</code>

Here, the synBlock method contains a synchronized block that uses lock as the monitor; thread T2 must wait for T1 to release the lock before entering the block.

2.5 Class Lock

In Java, the synchronized keyword can also be applied to static methods or to a synchronized block whose lock object is a Class object, creating a class lock. A class lock ensures that only one thread can execute any synchronized static method or block of that class at a time, even across different instances.

2.5.1 Class Lock: Static Method

When synchronized decorates a static method, the JVM implicitly acquires the class’s lock. Other threads attempting to enter any static synchronized method of the same class will be blocked until the first thread exits.

Code Example:

<code>public class ClassLockExample {
    public static synchronized void staticSyncMethod() {
        System.out.println("Thread " + Thread.currentThread().getName() + " is executing staticSyncMethod.");
        // Simulate method execution
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread " + Thread.currentThread().getName() + " has finished executing staticSyncMethod.");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(ClassLockExample::staticSyncMethod, "T1");
        Thread t2 = new Thread(ClassLockExample::staticSyncMethod, "T2");
        t1.start();
        t2.start();
    }
}
</code>

In this example, thread T2 must wait for T1 to release the class lock before it can execute staticSyncMethod .

2.5.2 Class Lock: Explicit Class Object

Besides static methods, a class lock can be created by explicitly using ClassName.class as the lock object in a synchronized block.

Code Example:

<code>public class ExplicitClassLockExample {
    public static void staticSyncBlock() {
        System.out.println("Thread " + Thread.currentThread().getName() + " is trying to enter staticSyncBlock.");
        synchronized (ExplicitClassLockExample.class) {
            System.out.println("Thread " + Thread.currentThread().getName() + " has entered staticSyncBlock.");
            // Simulate block execution
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " is leaving staticSyncBlock.");
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(ExplicitClassLockExample::staticSyncBlock, "T1");
        Thread t2 = new Thread(ExplicitClassLockExample::staticSyncBlock, "T2");
        t1.start();
        t2.start();
    }
}
</code>

Here, the synchronized block uses ExplicitClassLockExample.class as the lock, achieving the same class‑level mutual exclusion as a static synchronized method.

3 Summary

Object locks apply to individual instances; each instance has its own monitor lock, preventing concurrent access to synchronized code on the same object.

Class locks, created by synchronizing static methods or using a Class object as the lock, ensure that only one thread can execute class‑level synchronized code at a time, protecting static data from concurrent interference.

By properly using synchronized object locks and class locks, developers can effectively control concurrent access in multithreaded environments, guaranteeing data consistency and safety.

JavaconcurrencyThread Safetysynchronizedobject lock
Architecture & Thinking
Written by

Architecture & Thinking

🍭 Frontline tech director and chief architect at top-tier companies 🥝 Years of deep experience in internet, e‑commerce, social, and finance sectors 🌾 Committed to publishing high‑quality articles covering core technologies of leading internet firms, application architecture, and AI breakthroughs.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.