Codectionary / Developer documentation / Java

synchronized Keyword

The synchronized keyword prevents multiple threads from executing a block of code (or a method) at the same time on the same object, protecting shared, mutable data from race conditions. When one thread enters a synchronized block, it acquires a lock on the specified object; any other thread trying to enter a synchronized block on that same object must wait until the lock is released.

Syntax

synchronized (lockObject) {\n  // critical section\n}

Examples

The Problem Without Synchronization

Multiple threads incrementing a shared counter can produce an incorrect result due to a race condition.

class Counter {
    private int count = 0;

    public void increment() {  // NOT thread-safe
        count++;  // this is actually three steps: read, add, write
    }

    public int getCount() {
        return count;
    }
}

// Without synchronization, running this with multiple threads can produce
// a final count LESS than expected, because increments can be lost
// when two threads read the same value before either writes back.

synchronized Method

Marking an entire method as synchronized, so only one thread can execute it at a time per object.

class Counter {
    private int count = 0;

    public synchronized void increment() {  // now thread-safe
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

Counter counter = new Counter();
Runnable task = () -> {
    for (int i = 0; i < 1000; i++) counter.increment();
};

Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();

synchronized Block

Synchronizing only the specific critical section, rather than an entire method, for finer-grained control.

class BankAccount {
    private double balance = 100;
    private final Object lock = new Object();

    public void withdraw(double amount) {
        synchronized (lock) {  // only this block is protected
            if (amount <= balance) {
                balance -= amount;
            }
        }
        // other, non-critical work can happen outside the lock
    }
}

Best practices

  • Synchronize the smallest block of code necessary (a synchronized block) rather than an entire large method, to minimize how long threads wait on each other
  • Always synchronize on a private, final lock object rather than "this" when possible, to prevent external code from accidentally locking on the same object
  • Keep synchronized blocks free of slow operations (like network calls or file I/O) - holding a lock for a long time hurts overall concurrency
  • Consider higher-level concurrency utilities from java.util.concurrent (like AtomicInteger or ConcurrentHashMap) instead of manual synchronized blocks when they fit your use case

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading