Definition
- Static synchronized –
public static synchronized void audit()locks onClassName.class. This is one lock shared by all instances of the class. - Instance synchronized –
public synchronized void debit()locks onthis, the specific object instance. Each instance has its own lock. - Different locks – because the Class object and
thisare 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
thislock and block each other. Two instance synchronized methods called on different objects use differentthislocks 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.
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.
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.
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();
}
}
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.
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
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.
---