Back to Synchronization
Q4Question 4 of 8

What is static vs instance synchronized?

Key Concepts
  • A static synchronized method locks on the Class object (ClassName.class), shared by all instances.
  • An instance synchronized method locks on this, the specific object instance.
  • These are two different locks, so a static and an instance synchronized method can run simultaneously.
  • Two instance synchronized methods on the same object share the same this lock and block each other.
  • Two instance synchronized methods on different objects have different this locks and run in parallel.
  • If both must be mutually exclusive, use a shared static final lock object explicitly.

Definition

Static synchronized locks on the Class object while instance synchronized locks on this, and because they are different locks, they can execute simultaneously.
  • Static synchronized – public static synchronized void audit() locks on ClassName.class. This is one lock shared by all instances of the class.
  • Instance synchronized – public synchronized void debit() locks on this, the specific object instance. Each instance has its own lock.
  • Different locks – because the Class object and this are different objects, a static synchronized method and an instance synchronized method can run at the same time on the same object.
  • Same lock – two instance synchronized methods called on the same object use the same this lock and block each other. Two instance synchronized methods called on different objects use different this locks and run in parallel.

The bank has two padlocks: one on the main vault door (Class lock, shared by all branches) and one on Rajesh's personal drawer (instance lock, specific to Rajesh's account). A teller locking the vault door does not prevent another teller from opening Rajesh's drawer because they are different padlocks. Only when two tellers try to use the same padlock does one have to wait.

Understanding the Concepts

What lock does a static synchronized method use?

A static synchronized method locks on the Class object. There is only one Class object per class in the JVM, so this lock is shared by all instances and all threads.

JAVA
package com.bank.service;

public class AccountService {
    // Locks on AccountService.class
    public static synchronized void globalAudit() {
        System.out.println("Audit running on " + Thread.currentThread().getName());
        try { Thread.sleep(2000); } catch (InterruptedException e) { }
    }

    // Equivalent explicit form
    public static void globalAuditExplicit() {
        synchronized (AccountService.class) {
            System.out.println("Audit running");
        }
    }
}

What lock does an instance synchronized method use?

An instance synchronized method locks on this, the specific object instance.

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class AccountService {
    private BigDecimal balance = new BigDecimal("100000.00");

    // Locks on 'this'
    public synchronized void debit(BigDecimal amount) {
        balance = balance.subtract(amount);
    }

    // Also locks on 'this': same lock as debit()
    public synchronized BigDecimal getBalance() {
        return balance;
    }
}

Can static and instance synchronized run at the same time?

Yes. They use different lock objects, so they do not block each other.

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class ConcurrentLockDemo {
    private BigDecimal balance = new BigDecimal("100000.00");

    public static synchronized void globalAudit() {
        // Locks on ConcurrentLockDemo.class
        System.out.println("Audit on " + Thread.currentThread().getName());
        try { Thread.sleep(2000); } catch (InterruptedException e) { }
    }

    public synchronized void debit(BigDecimal amount) {
        // Locks on 'this'
        balance = balance.subtract(amount);
        System.out.println("Debit on " + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ConcurrentLockDemo service = new ConcurrentLockDemo();

        // These two run in PARALLEL because they use different locks
        new Thread(ConcurrentLockDemo::globalAudit, "AuditThread").start();
        new Thread(() -> service.debit(new BigDecimal("5000")), "DebitThread").start();
    }
}
TEXT
Audit on AuditThread
Debit on DebitThread

Both threads run simultaneously because globalAudit() locks on ConcurrentLockDemo.class while debit() locks on the service instance.

What is the complete lock combination matrix?

| Combination | Lock objects | Blocks? |
|---|---|---|
| static sync + static sync (same class) | Same Class lock | Yes |
| instance sync + instance sync (same object) | Same this | Yes |
| instance sync + instance sync (different objects) | Different this | No (parallel) |
| static sync + instance sync | Class vs this | No (parallel) |

What if both methods need to be mutually exclusive?

If the audit must prevent debits during its execution, both methods must use the same lock object.

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class SharedLockService {
    private static final Object SHARED_LOCK = new Object();
    private BigDecimal balance = new BigDecimal("100000.00");

    public static void globalAudit() {
        synchronized (SHARED_LOCK) {
            System.out.println("Audit: no debits can happen now");
        }
    }

    public void debit(BigDecimal amount) {
        synchronized (SHARED_LOCK) {
            balance = balance.subtract(amount);
        }
    }
}

What are common mistakes?

Developers often assume that all synchronized methods on an object block each other. This is only true for instance methods on the same instance. A static synchronized method uses a completely different lock.

What should a senior engineer know?

  • Class lock contention: a static synchronized method blocks ALL threads across ALL instances. If globalAudit() takes 10 seconds, no thread in the entire JVM can call any other static synchronized method on that class.
  • Prefer instance-level locking: static synchronization is a global bottleneck. Use it only when the operation truly needs JVM-wide exclusion.
  • ReadWriteLock for audits: if the audit only reads data, use a ReadWriteLock. Multiple audit threads can run concurrently (read lock), and debits take the write lock for exclusive access.

Visual Overview

DIAGRAM
  Lock Objects:

  ┌──────────────────────────┐
  │ AccountService.class      │ ◀── static synchronized methods lock here
  │ (ONE per class in JVM)    │
  └──────────────────────────┘

  ┌──────────────────────────┐   ┌──────────────────────────┐
  │ instance1 (this)          │   │ instance2 (this)          │
  │ debit() locks here        │   │ debit() locks here        │
  └──────────────────────────┘   └──────────────────────────┘
  ◀── instance synchronized        ◀── different lock: parallel!
       methods lock here

  Static sync + Instance sync = DIFFERENT locks = PARALLEL
  Instance sync (obj1) + Instance sync (obj2) = DIFFERENT locks = PARALLEL
  Instance sync (obj1) + Instance sync (obj1) = SAME lock = BLOCKED

Key Takeaway

A static synchronized method locks on the Class object, while an instance synchronized method locks on this. These are different lock objects, so they can execute simultaneously. This surprises developers who expect all synchronized methods to be mutually exclusive. They are only mutually exclusive when they share the same lock.

The practical implication: if your globalAudit() (static synchronized) needs to prevent debits (instance synchronized) during the report, both must use the same lock object. The default Class-vs-this separation will not help. Use a private static final Object SHARED_LOCK and synchronize both methods on it.

Remember one sentence: static synchronized locks on the Class object, instance synchronized locks on this, and because they are different locks, they can run in parallel.

---

Share
Use ← → arrow keys to navigate