Object-Level vs Class-Level Locking in Java

25 Apr 2026, Updated: 12 Jul 2026 3 min read
2
Sometimes each object instance should have its own independent lock, while in other cases all instances of a class must share a common lock. These two approaches are known as object-level locking and class-level locking.

In this article, we will explore how both models work, understand static synchronization, and discuss the important concept of lock granularity.

Object-Level Locking

Object-level locking means the lock belongs to a specific object instance. Each object has its own monitor lock, so threads working with different objects do not block each other.

When a non-static synchronized method is used, Java synchronizes on this (the current object).
class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}
Here, if two threads call increment() on the same Counter object, one must wait. But if they use two different Counter objects, both can run simultaneously.
Counter c1 = new Counter();
Counter c2 = new Counter();

// Threads synchronizing on c1 and c2 do not block each other
This improves concurrency because independent objects do not share the same lock.

Class-Level Locking

Class-level locking means the lock belongs to the Class object, not to any specific instance. Since there is only one Class object per loaded class, all instances share the same lock.

This is commonly used when protecting static data shared across every instance.
class Counter {
    private static int total = 0;

    public static synchronized void incrementTotal() {
        total++;
    }
}
Here, the method locks on:
Counter.class
So even if multiple objects exist, only one thread at a time can execute incrementTotal(). When a static method is declared synchronized, Java uses the class-level monitor lock automatically.
class Printer {
    public static synchronized void print() {
        System.out.println("Printing...");
    }
}
Equivalent form using synchronized block:
class Printer {
    public static void print() {
        synchronized (Printer.class) {
            System.out.println("Printing...");
        }
    }
}
Both versions synchronize on the same lock: Printer.class.
An important point is that object locks and class locks are different locks. That means a thread can execute a synchronized instance method while another thread executes a synchronized static method at the same time.
class Demo {
    public synchronized void methodA() { }
    public static synchronized void methodB() { }
}
- methodA() locks object instance
- methodB() locks Demo.class

These do not block each other unless additional logic causes contention.

Lock Granularity

Lock granularity refers to how large or small the locked region is and how broad the lock scope becomes.

Fine-grained locking means smaller, more specific locks. Coarse-grained locking means larger, broader locks covering more code or more resources.

Coarse-Grained Locking

public synchronized void processAll() {
    updateA();
    updateB();
    updateC();
}
One lock protects everything.

Fine-Grained Locking

private final Object lockA = new Object();
private final Object lockB = new Object();

public void updateA() {
    synchronized (lockA) {
        // update A
    }
}

public void updateB() {
    synchronized (lockB) {
        // update B
    }
}
Different resources use different locks.
Synchronizing static data with instance locks is incorrect.
class Wrong {
    private static int total = 0;

    public synchronized void increment() {
        total++; // unsafe across multiple instances
    }
}
Each object has its own lock, but total is shared globally. Different instances can update it concurrently.

Correct solution:
public static synchronized void increment() {
    total++;
}
In the next article, we will explore the volatile keyword and understand how Java guarantees memory visibility between threads.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion