Synchronized Methods in Java

Naveen AnamaneniUpdated · 3 min read

A synchronized method in Java is a method declared with the synchronized keyword. Before a thread can run it, the thread must take the lock of the object the method is called on (this). So, for one object, only one thread at a time can be inside any of its synchronized instance methods. This is the simplest way to protect an object's fields from race conditions. In this lesson, you will learn the syntax, see a thread-safe class, and learn what synchronized methods cost.

Syntax

Syntax
public synchronized void deposit(int amount) {
    balance += amount;
}
MethodLock taken
synchronized instance methodThe object itself (this)
static synchronized methodThe class object (Account.class)

Example: A Thread-Safe Account

Let's see an example of a class whose methods are all synchronized.

SafeAccount.java▶ Try it
public class SafeAccount {
    private int balance;
 
    public synchronized void deposit(int amount) {
        balance += amount;
    }
 
    public synchronized boolean withdraw(int amount) {
        if (balance >= amount) {
            balance -= amount;
            return true;
        }
        return false;
    }
 
    public synchronized int getBalance() {
        return balance;
    }
 
    public static void main(String[] args) throws InterruptedException {
        SafeAccount account = new SafeAccount();
        Thread navika = new Thread(() -> {
            for (int i = 0; i < 1000; i++) account.deposit(10);
        });
        int[] successes = new int[1];
        Thread advitha = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                if (account.withdraw(5)) successes[0]++;
            }
        });
        navika.start();
        advitha.start();
        navika.join();
        advitha.join();
 
        int expected = 1000 * 10 - successes[0] * 5;
        System.out.println("Balance at least 5000? "
            + (account.getBalance() >= 5000));
        System.out.println("Deposits minus withdrawals match the balance? "
            + (account.getBalance() == expected));
    }
}
Output
Balance at least 5000? true
Deposits minus withdrawals match the balance? true

Explanation: All three methods lock the same account object, so a deposit and a withdrawal never overlap. withdraw checks and subtracts in one locked step, so the balance can't go below zero. Some withdrawals may happen before deposits arrive and fail, so the exact final balance can vary. The program counts the successful withdrawals and checks that the balance equals all deposits minus exactly those withdrawals: no update was lost.

Costs and Limits

  • Coarse locking: the whole method holds the lock, even parts that don't touch shared data.
  • Contention: many threads calling the same object queue up.
  • Different objects don't exclude each other: two threads using two accounts run in parallel, which is usually what you want.

Common Mistakes

Synchronizing the setter but not the getter. The getter may return a stale value.

Calling a slow external service inside a synchronized method. Every caller waits.

Assuming synchronized on one object protects data in another object. Each object has its own lock.

Practice

  1. Easy: Make a Counter class with synchronized increment and get methods and test it with three threads.
  2. Harder: Add a transfer(SafeAccount to, int amount) method and think about what happens when two threads transfer in opposite directions at once (hint: see "Deadlock in Java").

Quick check: Synchronized methods

4 questions
1Which lock does a synchronized instance method take?
2Which lock does a static synchronized method take?
3Can two threads run synchronized methods on two different objects at once?
4Why synchronize the getter too?

Key Takeaways

Was this tutorial helpful?

Lesson 398 of 482