Understanding Instance and Class Level Locking in Java

Instance-Level Locking

In Java, when you apply the synchronized keyword to a non-static method, the lock is associated with the specific object instance (this). This ensures that only one thread can execute any synchronized instance method on that particular object at a time.

Race Condition in Instance Members

Consider a scenario where two fields must remain consistent relative to each other. Without proper synchronization, concurrent access can lead to inconsistent states.

public class MetricsTracker {
    private long primaryCount = 0;
    private long secondaryCount = 0;

    public void update() {
        for (int i = 0; i < 10000; i++) {
            primaryCount++;
            secondaryCount++;
        }
    }

    public void verify() {
        for (int i = 0; i < 10000; i++) {
            if (primaryCount < secondaryCount) {
                System.out.println("Inconsistency: " + primaryCount + " / " + secondaryCount);
            }
        }
    }
}

If one thread executes update() while another executes verify() on the same instance, the verification thread might read primaryCount after it has been incremented but before secondaryCount is updated, resulting in an inconsistent view of the data.

Applying Instance Locks

To resolve this, we synchronize the instance methods. This forces threads to acquire the instance's monitor before entering these blocks.

public class MetricsTracker {
    private long primaryCount = 0;
    private long secondaryCount = 0;

    public synchronized void update() {
        for (int i = 0; i < 10000; i++) {
            primaryCount++;
            secondaryCount++;
        }
    }

    public synchronized void verify() {
        for (int i = 0; i < 10000; i++) {
            if (primaryCount < secondaryCount) {
                System.out.println("Consistent state maintained.");
            }
        }
    }
}

Class-Level Locking

Class-level locking is required when you need to protect static fields that are shared across all instances of a class. An instance-level lock only protects the state of a single object; it does nothing to prevent race conditions on static variables accessed by diffreent instances.

The Limitation of Instance Locks on Static Data

In the following example, multiple instances are created, and each calls a instance-synchronized method to modify a shared static variable.

public class GlobalInventory {
    private static int totalItems = 0;

    // This lock belongs to the 'this' instance, not the class
    public synchronized void addItem() {
        totalItems++;
    }

    public static int getTotalItems() {
        return totalItems;
    }
}

// Execution logic
IntStream.rangeClosed(1, 1000).parallel().forEach(i -> {
    new GlobalInventory().addItem();
});

In this case, totalItems will likely be less than 1000. Because every iteration creates a new GlobalInventory(), each thread acquires a different lock (one per instance), allowing multiple threads to modify the static totalItems simultaneously.

Implementing Class-Level Synchronization

To secure static data, you must lock on the Class object itself or a static reference object. This ensures that only one thread can access the protected logic, regardless of which instance is used.

public class GlobalInventory {
    private static int totalItems = 0;
    private static final Object internalLock = new Object();

    public void addItem() {
        // Synchronizing on a static object provides a class-level lock
        synchronized (internalLock) {
            totalItems++;
        }
    }

    // Alternatively, use a static synchronized method
    public static synchronized void staticAddItem() {
        totalItems++;
    }

    public static int getTotalItems() {
        return totalItems;
    }
}

By using a static lock, all instances of GlobalInventory will compete for the same moniter, ensuring that the totalItems counter is incremented atomically across the entire application.

Tags: java Concurrency multithreading Synchronized JVM

Posted on Fri, 12 Jun 2026 17:42:24 +0000 by mallard