In multithreaded environments, multiple threads may access shared data simultaneously, leading to:

  • race conditions,
  • inconsistent results,
  • unexpected behavior.

Synchronization ensures only one thread can access a critical section at a time.

Synchronized Keyword

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

Locks the entire method - only one thread at a time can execute it per object.

Synchronized Block

public void increment() {
    syncronized (this) {
        count++;
    }
}

Finer control - only part of the method is locked.

Static Synchronization

public static synchronized void log() {
    // locks the class, not the instance
}

Used when you want to lock on the class object.

Common Problem: Race Condition

// Two threads modify 'count' at the same time → inconsistent result
count++; // not atomic!

Use synchronization to prevent this.

Java Lock API (java.util.concurrent.locks)

Lock lock = new ReentrantLock();
 
lock.lock();
try {
    // critical section
} finally {
    lock.unlock();
}

Gives more control than synchronized (e.g. try-lock, fair locks).

Comparison

synchronized vs Lock

FeaturesynchronizedLock (ReentrantLock)
Simpler syntaxYesNo (verbose)
Explicit unlockNoYes (manual)
Try-lockNot supportedSupported
ReentrancyYesYes

Tip

Be ready to:

  • explain what race conditions are and how to prevent them,
  • write synchronized methods/blocks,
  • compare synchronized vs ReentrantLock,
  • mention the importance of unlocking in a finally block.

Parent: _Multithreading