Synchronized Methods in Java
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
public synchronized void deposit(int amount) {
balance += amount;
}| Method | Lock taken |
|---|---|
synchronized instance method | The object itself (this) |
static synchronized method | The class object (Account.class) |
Example: A Thread-Safe Account
Let's see an example of a class whose methods are all synchronized.
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));
}
}Balance at least 5000? true
Deposits minus withdrawals match the balance? trueExplanation: 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
- Easy: Make a
Counterclass with synchronizedincrementandgetmethods and test it with three threads. - 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").
Key Takeaways
Was this tutorial helpful?