Static Synchronization in Java

Naveen AnamaneniUpdated · 3 min read

Static synchronization in Java means synchronizing on the class rather than on an object. A static synchronized method takes the lock of the Class object (such as Ticket.class), so only one thread at a time can run any static synchronized method of that class. It is used to protect static fields, which are shared by all objects of the class. Synchronizing on this can't protect them, because different objects have different locks. In this lesson, you will learn static synchronization and the mistake it fixes.

Syntax

Syntax
public static synchronized int nextNumber() { ... }
 
// same lock, written as a block:
synchronized (Ticket.class) { ... }

Example: Unique Ticket Numbers

Let's see an example where every new ticket must get a unique number from a static counter. The class has two ways to get a number: a wrong one that locks this, and a right one that locks the class.

Ticket.java▶ Try it
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
public class Ticket {
    private static int next = 0;
    private static int nextUnsafe = 0;
 
    static synchronized int nextNumber() {
        return ++next;
    }
 
    synchronized int nextNumberWrongLock() {
        return ++nextUnsafe;
    }
 
    public static void main(String[] args) throws InterruptedException {
        Set<Integer> good =
            java.util.Collections.synchronizedSet(new HashSet<>());
        List<Thread> threads = new ArrayList<>();
        for (int t = 0; t < 4; t++) {
            Thread th = new Thread(() -> {
                Ticket mine = new Ticket();
                for (int i = 0; i < 50_000; i++) {
                    good.add(nextNumber());
                    mine.nextNumberWrongLock();
                }
            });
            threads.add(th);
            th.start();
        }
        for (Thread th : threads) {
            th.join();
        }
        System.out.println("Class lock: " + good.size() + " unique numbers");
        System.out.println("Object lock reached 200000? "
            + (nextUnsafe == 200_000));
    }
}
Output
Class lock: 200000 unique numbers
Object lock reached 200000? false

Explanation: nextNumber is static synchronized, so all four threads share one lock, Ticket.class, and all 200,000 numbers are unique. nextNumberWrongLock is an instance method: each thread locks its own Ticket object, so the threads don't exclude each other while they all change the same static field, and updates are lost. (On rare runs the wrong version might still reach 200,000 by luck, which is why the output is marked as a sample.)

Static and Instance Locks Are Separate

Common Mistakes

Protecting a static field with an instance lock. Every object has its own lock, so threads don't wait for each other.

Mixing static and instance synchronized methods on the same data. They use different locks.

Holding the class lock for slow work. It blocks every thread using any static synchronized method of the class.

Practice

  1. Easy: Write a class with a static synchronized method that returns the next order ID, and test it with three threads.
  2. Harder: Rewrite nextNumber as an AtomicInteger and compare the code.

Quick check: Static synchronization

4 questions
1Which lock does a static synchronized method use?
2Why can't an instance lock protect a static field?
3Do a static synchronized method and an instance synchronized method of the same class block each other?
4Which block is equivalent to a static synchronized method of Ticket?

Key Takeaways

Was this tutorial helpful?

Lesson 400 of 482