Fundamentals 9 min read

Mastering Java Locks: Ensure Atomicity and Avoid Concurrency Bugs

This article explains the root cause of atomicity issues in multithreaded Java programs, introduces mutex concepts, demonstrates three synchronized lock usages with code examples, discusses critical sections, lock granularity, and common pitfalls, and provides practical guidelines for correctly protecting shared resources.

Programmer DD
Programmer DD
Programmer DD
Mastering Java Locks: Ensure Atomicity and Avoid Concurrency Bugs

Atomicity problems originate from thread switching; a mutex guarantees that only one thread can execute at a time.

Mutex: only one thread executes at any moment.

In Java, the most common way to achieve mutual exclusion is using locks, especially the built‑in synchronized keyword.

Lock

Below are three typical usages of synchronized in Java:

public class ThreeSync {
    private static final Object object = new Object();

    public synchronized void normalSyncMethod() {
        // critical section
    }

    public static synchronized void staticSyncMethod() {
        // critical section
    }

    public void syncBlockMethod() {
        synchronized (object) {
            // critical section
        }
    }
}

The three forms differ in what they lock:

Instance method: locks the current instance (usually this).

Static method: locks the Class object (e.g., ThreeSync.class).

Synchronized block: locks the object specified in the parentheses.

Critical section: the code that must be executed mutually exclusively.

Effective locking means clearly identifying what you lock and what resource you protect. The lock must guard the shared variable (resource R) you intend to protect.

Illustrations:

Two key questions when using locks:

What are we locking?

What resource are we protecting?

If the lock does not protect the intended resource, concurrency bugs will appear.

Example of a correctly scoped lock:

public class ValidLock {
    private static final Object object = new Object();
    private int count;

    public synchronized void badSync() {
        // unrelated logic
        count++;
    }

    public void goodSync() {
        // unrelated logic
        synchronized (object) {
            count++;
        }
    }
}

Note: using the appropriate lock granularity improves efficiency.

Typical counter implementation with synchronized:

public class SafeCounter {
    private int count;

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

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

Even read‑only methods should be synchronized to respect the happens‑before rule:

Unlocking a lock happens‑before a subsequent lock acquisition on the same monitor.

Otherwise, writes may not be visible to reads, leading to dirty reads.

Using multiple different locks to protect the same variable is ineffective:

public class UnsafeCounter {
    private static int count;

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

    public static synchronized int calc() {
        return count++;
    }
}

Two locks ( this and UnsafeCounter.class) protect the same variable, so the critical sections are not mutually exclusive and the variable remains unprotected.

Summary

Solving atomicity requires mutual exclusion so intermediate states are invisible.

Locks are the key; you must know what you lock and what resource you protect, and ensure the lock actually guards that resource.

An effective critical section has a single entry and exit; multiple locks protecting the same resource create parallel entrances and defeats mutual exclusion.

Lock granularity matters: locking a whole system when only a small part needs protection harms performance.

Soulful Questions

Will using multiple locks on one resource always cause problems?

When is it necessary to lock a whole “neighborhood” instead of a single “house”?

In a bank transfer scenario, what lock granularity is appropriate for two‑person transfers versus external transfers?

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaatomicity
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.