Fundamentals 20 min read

Understanding Thread Safety, Synchronization, and Locks in Java

This article explains the fundamentals of thread safety in Java, illustrating common pitfalls in producer‑consumer scenarios, demonstrating how synchronized, wait/notify, and the explicit Lock/Condition mechanisms can be used to avoid data races, deadlocks, and inconsistent state while providing complete code examples.

Top Architect
Top Architect
Top Architect
Understanding Thread Safety, Synchronization, and Locks in Java

Thread safety is a core concept for writing high‑quality, high‑performance Java code; it involves ensuring that multiple threads can safely access shared resources without causing data corruption, deadlocks, or inconsistent state.

The article starts with a producer‑consumer example where a Resource class represents a vehicle, and two runnable tasks ( Input as producer and Output as consumer) manipulate the same object without proper synchronization, leading to missing wheels and duplicate consumption.

public class Resource {
    private int id;
    private String name;
    private int wheelNumber;
    private boolean flag = false;
    // getters/setters omitted
    @Override
    public String toString() {
        return "id=" + id + "--- name=" + name + "--- wheelNumber=" + wheelNumber;
    }
}
public class Input implements Runnable {
    private Resource r;
    public Input(Resource r) { this.r = r; }
    public void run() {
        for (int i = 0;; i++) {
            if (i % 2 == 0) { r.setId(i); r.setName("小汽车"); r.setWheelNumber(4); }
            else { r.setId(i); r.setName("电动车"); r.setWheelNumber(2); }
        }
    }
}
public class Output implements Runnable {
    private Resource r;
    public Output(Resource r) { this.r = r; }
    public void run() {
        for (;;) {
            System.out.println(r.toString());
        }
    }
}

Because the producer and consumer modify the shared Resource without coordination, the CPU may interleave operations, causing the consumer to read partially updated fields (e.g., a car with missing wheels) or to consume the same object multiple times.

To fix the race, the article introduces synchronized blocks around the critical sections, ensuring that only one thread can modify or read the resource at a time.

public void run() {
    for (int i = 0;; i++) {
        synchronized (r) {
            if (i % 2 == 0) { r.setId(i); r.setName("小汽车"); r.setWheelNumber(4); }
            else { r.setId(i); r.setName("电动车"); r.setWheelNumber(2); }
        }
    }
}

While synchronized prevents simultaneous access, it does not solve the producer‑consumer coordination problem. The article then adds wait() and notify() to make the producer wait when the resource is already produced (flag true) and the consumer wait when the resource is empty (flag false).

public void run() {
    for (int i = 0;; i++) {
        synchronized (r) {
            while (r.isFlag()) {
                try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
            }
            // produce item
            r.setFlag(true);
            r.notify();
        }
    }
}

public void run() {
    for (;;) {
        synchronized (r) {
            while (!r.isFlag()) {
                try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
            }
            System.out.println(r.toString());
            r.setFlag(false);
            r.notify();
        }
    }
}

Even with wait/notify, using notify() can cause deadlocks when multiple producer or consumer threads are present, because the awakened thread may be of the same type, leaving all others waiting. The article demonstrates this with a multi‑producer/multi‑consumer scenario where some items are never consumed and others are printed repeatedly.

To avoid this, the article suggests replacing if checks with while loops (re‑checking the flag after being notified) and using notifyAll() to wake all waiting threads, ensuring progress.

Finally, the article presents a more elegant solution using the explicit Lock and Condition classes introduced in Java 1.5. Separate conditions for producers ( in_con) and consumers ( out_con) allow precise signaling without waking unrelated threads.

class Input implements Runnable {
    private Resource r; private Lock lock; private Condition inCon; private Condition outCon; private int i = 0;
    public void run() {
        for (;;) {
            lock.lock();
            while (r.isFlag()) { inCon.await(); }
            // produce item
            r.setFlag(true);
            outCon.signal();
            lock.unlock();
        }
    }
}

class Output implements Runnable {
    private Resource r; private Lock lock; private Condition inCon; private Condition outCon;
    public void run() {
        for (;;) {
            lock.lock();
            while (!r.isFlag()) { outCon.await(); }
            System.out.println(r.toString());
            r.setFlag(false);
            inCon.signal();
            lock.unlock();
        }
    }
}

With Lock / Condition, the producer and consumer coordinate precisely, eliminating the deadlock and performance issues observed with plain synchronized and notify(). The article concludes with a concise list of key take‑aways about multithreading, synchronization, and lock usage.

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.

JavaconcurrencySynchronizationthread safetyLock
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.