Synchronized: what it is, principle of operation, and usage in Java

Author: IT Sectr Published: 2026-03-19 Reading time: 8 min

Synchronized is a built-in synchronization mechanism in the Java language that provides exclusive access to critical sections of code. According to Oracle, 2024, the synchronized modifier guarantees that only one thread can execute the marked method or block at a specific moment in time. This mechanism is based on monitors — a fundamental concept of operating systems that ensures correct operation of multithreaded applications of all complexity levels.

Key Takeaways

  • Synchronized — Java keyword for thread-safe data access.
  • Object monitor — the internal mechanism on which synchronization is based.
  • Synchronized method locks the entire method at the instance or class level.
  • Synchronized block allows synchronizing only part of the code.
  • Deadlock — one of the main problems with nested synchronization.

What is synchronized?

Synchronized is a keyword in Java that guarantees that only one thread executes a protected section of code at any given time, preventing data corruption during concurrent access. It appeared in the first version of Java and remains the simplest way to ensure thread safety for developers of any skill level.

Definition and role in Java

The synchronized modifier solves two tasks: mutual exclusion and visibility of changes. When a thread exits a synchronized block, all changes are guaranteed to be visible to other threads entering a block synchronized on the same object.

Synchronized can be applied to an entire method or to an arbitrary block of code specifying a monitor object. In both cases, the JVM inserts monitorenter and monitorexit instructions at the bytecode level.

Prerequisites for emergence

In multithreaded applications without synchronization, a race condition occurs — when two threads simultaneously modify the same data, leading to unpredictable results. Synchronized became Java's first and primary tool for combating this problem, providing a simple declarative syntax accessible to any developer.

How does synchronized work?

The synchronized mechanism is based on the concept of a monitor — a high-level synchronization primitive built into every Java object. The monitor is associated with an object when a synchronized block is first used on it.

Object monitor

Every object in Java has an associated monitor. When a thread enters a synchronized block, it acquires the object's monitor. If the monitor is already held by another thread, the thread blocks until it is released. In bytecode, this corresponds to the monitorenter and monitorexit instruction pair.

Lock states (biased locking)

The JVM optimizes synchronized through several levels: biased locking for single-thread access, lightweight locking for low contention, and heavyweight locking for intense contention involving the OS. These levels improve performance without changing the code.

java
class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

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

Happens-before rule

Synchronized establishes a happens-before relationship: all actions in a thread before exiting a synchronized block are visible to another thread after entering a block synchronized on the same object. This guarantees not only mutual exclusion but also data consistency for all threads.

Synchronized method vs block

Java offers two ways to apply synchronized: at the method level and at the block level. The choice between them affects performance and synchronization granularity.

Synchronized method

Marking a method with the synchronized modifier automatically synchronizes it on the current instance (for instance methods) or on the Class object (for static methods). This is the simplest way to ensure mutual exclusion, but it is often excessive if the critical section constitutes only a small part of the method, and the remaining code does not require synchronization.

Synchronized block

A synchronized block gives precise control: you specify the monitor object and synchronize only the necessary section of code, leaving the rest of the method outside the lock. This minimizes monitor hold time and improves overall application performance in a multithreaded environment, as other threads can concurrently execute unrelated code without waiting for the monitor to be released.

java
class DataProcessor {
    private final Object lock = new Object();

    public void process() {
        // code outside critical section - without synchronization
        prepareData()

        synchronized (lock) {
            // only this block is protected
            updateSharedState()
        }

        // execution continues without locking
        cleanup()
    }
}
CriterionSynchronized methodSynchronized block
Monitorthis (instance) or Classany object
Granularityentire methodonly needed code
Readabilityhighmedium
Performancelower for large methodshigher for small critical sections

Synchronized in Android

In Android development, synchronized is widely used to protect SharedPreferences, database access, and UI components. However, its use on the main thread is strongly discouraged due to the risk of interface freezing.

Usage with SharedPreferences

SharedPreferences in Android provides basic thread safety, but when editing from multiple threads through Editor, external synchronization may be required. A synchronized block with a separate lock object guarantees consistency of changes.

kotlin
class PreferencesManager(private val prefs: SharedPreferences) {
    private val lock = Any()

    fun writeToken(token: String) {
        synchronized (lock) {
            prefs.edit()
                .putString("auth_token", token)
                .apply()
        }
    }
}

Limitations in Android applications

The main limitation of synchronized on Android is thread blocking. Unlike coroutines with Mutex, synchronized blocks the entire system thread. On the main thread, this causes ANR. In modern Android development, synchronized is recommended to be replaced with coroutines (suspend Mutex) or atomic types (AtomicInteger).

Alternatives to synchronized

Modern Java and Kotlin offer several alternatives to synchronized, each solving the same problems with fewer limitations or better performance.

Lock from java.util.concurrent

The Lock interface with implementations ReentrantLock and ReadWriteLock provides timeouts, interruptible waiting, and multiple Condition queues. It is more flexible than synchronized but requires explicit release in finally, which increases the risk of error when unlock is forgotten.

Atomic classes

AtomicInteger, AtomicLong, AtomicReference and other classes use Lock-Free algorithms based on CAS (Compare-And-Swap). They are significantly faster than synchronized in scenarios with moderate contention because they do not block threads but perform optimistic retries without requiring OS kernel context switching.

ThreadLocal and thread safety

ThreadLocal provides an alternative approach: each ThreadLocal variable is isolated within a single thread and does not require synchronization for reading and writing. This completely eliminates the need for synchronized for data that should not be shared between threads. ThreadLocal is actively used in frameworks (Spring, Hibernate) for storing transaction context and sessions.

Coroutines and compose approach

In Kotlin projects for Android, an alternative to synchronized is Mutex from kotlinx.coroutines. It does not block the operating system thread but suspends the coroutine until the lock is released — this allows efficient use of pool threads and avoids ANR during long waits for resource release.

kotlin
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

val mutex = Mutex()
var counter = 0

suspend fun safeIncrement() {
    mutex.withLock {
        counter++
    }
}

Synchronized performance

The performance of synchronized has changed significantly in recent Java versions. It used to be considered a “heavy” mechanism, but modern JVMs have eliminated most overhead through advanced JIT compiler optimizations. Let's look in detail at how the virtual machine accelerates synchronized code at runtime.

Biased Locking and Lock Coarsening

The JVM JIT compiler applies several optimizations: biased locking eliminates synchronization if the lock is always acquired by the same thread; lock coarsening merges adjacent synchronized blocks into one; lock elimination removes synchronization if the object is only accessible by one thread. These optimizations make synchronized virtually free at low contention.

Measuring contention and choosing optimization

The JVM determines the contention level for each object: when there is no contention, biased locking is enabled; when a second thread appears, the lock transitions to lightweight mode with spin-waiting; and only during prolonged waiting does it escalate to heavyweight with a system mutex. This escalation happens automatically, and the developer does not need to manually choose a strategy.

Comparison with Lock and Atomic classes

In modern benchmarks (Java 17+), synchronized shows performance comparable to ReentrantLock at low and moderate contention. At high contention, Lock may have an advantage due to a more efficient wait queue with timeouts and interrupt support. For high-load systems where contention is constant, ReentrantLock with fair mode provides more predictable behavior.

Atomic classes (AtomicInteger, AtomicReference) remain the fastest for simple counters and flags thanks to Lock-Free CAS implementation. They do not block threads at all — on conflict, the operation simply retries in a loop. This gives a 3-5x performance boost compared to synchronized on counter increment operations with 4-8 threads.

Frequently Asked Questions

What is the difference between synchronized and volatile?

Synchronized provides both mutual exclusion and visibility. Volatile only guarantees visibility of changes — writing to a volatile variable is visible to all threads but does not prevent simultaneous modification, meaning it does not protect against race conditions.

Can synchronized cause a deadlock?

Yes, deadlock is possible with nested synchronization using different monitor orders. For example, one thread calls synchronized(a) { synchronized(b) }, while another calls synchronized(b) { synchronized(a) }. Avoid nested synchronized blocks or fix a consistent monitor ordering.

What is a monitor in Java?

A monitor is a synchronization mechanism associated with every Java object. It guarantees that only one thread executes synchronized code on that object. The monitor includes a lock, a wait queue, and a pool of threads waiting for notification via wait/notify.

Is Lock faster than synchronized?

In modern Java versions (17+), synchronized does not lag behind Lock in performance thanks to JIT optimizations (biased locking, lock coarsening). Lock is preferred not for speed but for additional capabilities: timeouts, interruptible waiting, and multiple Condition queues.

How does synchronized work with static methods?

A static synchronized method uses the monitor of the Class object of the given class, not the instance. This means synchronization applies across all instances of the class. Non-static and static synchronized methods use different monitors and do not block each other.

Summary

  • Synchronized — built-in Java synchronization mechanism based on monitors.
  • Object monitor — internal JVM structure ensuring mutual exclusion.
  • Wait/notify methods are used only inside synchronized blocks or methods.
  • Synchronized block is preferable to a method due to finer synchronization granularity.
  • Happens-before guarantees visibility of changes between threads when synchronizing on the same object.
  • Deadlock — the main risk with nested synchronization using different monitor ordering.
  • Alternatives — Lock, Atomic classes, and coroutines with suspending Mutex.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also