Why Your synchronized Block Fails: A Real‑World Java Thread‑Safety Case Study

A Java multithreading example shows that synchronizing on a mutable Integer field does not guarantee exclusive access, and the article explains the root cause, demonstrates correct locking techniques, and offers best‑practice tips for safe concurrent programming.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Why Your synchronized Block Fails: A Real‑World Java Thread‑Safety Case Study

Problematic Code

The article starts with a stripped‑down Java class SyncTest that implements Runnable. Two threads share a single SyncTest instance and increment a non‑final Integer count inside a synchronized(count) block, then sleep for 10 seconds.

public class SyncTest implements Runnable {

    private Integer count = 0;

    @Override
    public void run() {
        synchronized (count) {
            System.out.println(new Date() + " 开始休眠" + Thread.currentThread().getName());
            count++;
            try {
                Thread.sleep(10000);
                System.out.println(new Date() + " 结束休眠" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest test = new SyncTest();
        new Thread(test).start();
        Thread.sleep(100);
        new Thread(test).start();
    }
}

Running the program prints both threads’ "开始休眠" messages almost simultaneously, proving that the lock did not work.

Execution Result

Fri Jul 23 22:10:34 CST 2021 开始休眠Thread-0
Fri Jul 23 22:10:34 CST 2021 开始休眠Thread-1
Fri Jul 23 22:10:44 CST 2021 结束休眠Thread-0
Fri Jul 23 22:10:45 CST 2021 结束休眠Thread-1

The expectation was that the first thread would finish its critical section before the second entered, but the logs show concurrent entry.

synchronized Overview

The synchronized keyword can be applied in three ways:

Synchronize an instance method – locks the current object.

Synchronize a static method – locks the Class object.

Synchronize a block – locks the object specified in parentheses.

In the example the third form is used. The JVM inserts monitor.enter and monitor.exit bytecode instructions to acquire and release the monitor of the lock object.

Root Cause Analysis

IDE inspections warn: "Synchronization on a non‑final field 'count'" because the lock expression refers to a mutable object. Each thread may lock a different Integer instance (autoboxing creates a new object after count++), so the monitors are distinct and the lock is ineffective.

Synchronization on a non‑final field 'xxx' Inspection info: Reports synchronized statements where the lock expression is a reference to a non‑final field. Such statements are unlikely to have useful semantics, as different threads may be locking on different objects even when operating on the same object.

Corrected Implementation

Locking on the enclosing object ( this) ensures all threads synchronize on the same monitor:

public class SyncTest implements Runnable {

    private Integer count = 0;

    @Override
    public void run() {
        synchronized (this) {
            System.out.println(new Date() + " 开始休眠" + Thread.currentThread().getName());
            count++;
            try {
                Thread.sleep(10000);
                System.out.println(new Date() + " 结束休眠" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    // ...
}

Running the corrected program yields:

Fri Jul 23 23:13:55 CST 2021 开始休眠Thread-0
Fri Jul 23 23:14:05 CST 2021 结束休眠Thread-0
Fri Jul 23 23:14:05 CST 2021 开始休眠Thread-1
Fri Jul 23 23:14:15 CST 2021 结束休眠Thread-1

Now the second thread starts only after the first releases the lock.

Alternative: Dedicated Lock Object

Locking on this can cause unnecessary contention if other synchronized methods also use the same monitor. A common pattern is to create a private final lock object:

public class SyncTest implements Runnable {

    private Integer count = 0;
    private final Object locker = new Object();

    @Override
    public void run() {
        synchronized (locker) {
            System.out.println(new Date() + " 开始休眠" + Thread.currentThread().getName());
            count++;
            try {
                Thread.sleep(10000);
                System.out.println(new Date() + " 结束休眠" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Practical Tips for Using synchronized

Prefer private lock objects; expose them via getters only as immutable copies.

If the locked object is a mutable collection, synchronize the getter and return a defensive copy.

The lock is always an object, never a code fragment; different synchronized blocks on different objects do not coordinate.

Each object has a single associated monitor.

Excessive synchronization adds overhead and can lead to deadlocks—use it judiciously.

Conclusion

The case study highlights two key takeaways: never ignore IDE warnings about synchronization on mutable fields, and always ensure all threads lock on the same, preferably immutable, monitor object to achieve true thread safety.

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.

Javaconcurrencythread safetymultithreadingsynchronized
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

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.