Seven Synchronization Scenarios in Java: Thread‑Safety Analysis with Code Demonstrations

This article explains seven common Java synchronized usage scenarios, analyzes whether each case is thread‑safe, provides detailed code examples and execution results, and offers practical guidance for interview preparation and correct multithreading design.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Seven Synchronization Scenarios in Java: Thread‑Safety Analysis with Code Demonstrations

Introduction

This article introduces seven synchronized method usage scenarios that frequently appear in multithreaded Java programming and interview questions, explaining the thread‑safety of each case and the underlying lock mechanisms.

Scenario 1: Two threads invoke the same object's synchronized method

Analysis: Both threads compete for the same object lock, so they wait for each other and the execution is thread‑safe.

Conclusion: Thread‑safe.

Scenario 2: Two threads invoke synchronized methods on two different objects

Analysis: Each thread holds a separate object lock, so there is no contention and the execution is not thread‑safe.

Conclusion: Not thread‑safe.

Code verification

public class Condition2 implements Runnable {
    // create two different objects
    static Condition2 instance1 = new Condition2();
    static Condition2 instance2 = new Condition2();

    @Override
    public void run() {
        method();
    }

    private synchronized void method() {
        System.out.println("Thread name: " + Thread.currentThread().getName() + ", start");
        try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("Thread: " + Thread.currentThread().getName() + ", end");
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(instance1);
        Thread thread2 = new Thread(instance2);
        thread1.start();
        thread2.start();
        while (thread1.isAlive() || thread2.isAlive()) {}
        System.out.println("Test finished");
    }
}

Execution result

Both threads run in parallel, therefore the scenario is not thread‑safe.

Thread name: Thread-0, start
Thread name: Thread-1, start
Thread: Thread-0, end
Thread: Thread-1, end
Test finished

Scenario 3: Two threads invoke a static synchronized method (on one or two objects)

Using a class‑level lock solves the problem of Scenario 2; all threads compete for the same lock, making the execution thread‑safe.

Conclusion: Thread‑safe.

Scenario 4: One thread invokes a synchronized method while another invokes a non‑synchronized method

The non‑synchronized method is not affected by the lock, so the execution is not thread‑safe.

Conclusion: Not thread‑safe.

public class Condition4 implements Runnable {
    static Condition4 instance = new Condition4();

    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method0(); // synchronized
        }
        if (Thread.currentThread().getName().equals("Thread-1")) {
            method1(); // non‑synchronized
        }
    }

    private synchronized void method0() { /* ... */ }
    private void method1() { /* ... */ }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {}
        System.out.println("Test finished");
    }
}

Scenario 5: A synchronized method calls a non‑synchronized method

If the non‑synchronized method is called only from the synchronized method, the scenario can be thread‑safe; however, if any other thread calls the non‑synchronized method directly, thread‑safety is lost.

Conclusion: Thread‑safe only when the non‑synchronized method is never invoked directly by other threads.

public class Condition8 implements Runnable {
    static Condition8 instance = new Condition8();
    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method2(); // direct call to non‑synchronized method
        } else {
            method1(); // synchronized method that calls method2()
        }
    }
    private static synchronized void method1() { /* ... */ method2(); }
    private static void method2() { /* ... */ }
    public static void main(String[] args) { /* start three threads */ }
}

Scenario 6: Two threads invoke different synchronized methods on the same object

Both methods share the same object lock, so the execution is serialized and thread‑safe.

Conclusion: Thread‑safe.

public class Condition5 implements Runnable {
    static Condition5 instance = new Condition5();
    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) method0();
        if (Thread.currentThread().getName().equals("Thread-1")) method1();
    }
    private synchronized void method0() { /* ... */ }
    private synchronized void method1() { /* ... */ }
    public static void main(String[] args) { /* start two threads */ }
}

Scenario 7: One thread invokes a static synchronized method while another invokes a non‑static synchronized method

The static method uses a class‑level lock (Class object), whereas the non‑static method uses an instance lock (this). Since the locks differ, the threads run concurrently and the scenario is not thread‑safe.

Conclusion: Not thread‑safe.

public class Condition6 implements Runnable {
    static Condition6 instance = new Condition6();
    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) method0(); // static synchronized
        if (Thread.currentThread().getName().equals("Thread-1")) method1(); // instance synchronized
    }
    private static synchronized void method0() { /* ... */ }
    private synchronized void method1() { /* ... */ }
    public static void main(String[] args) { /* start two threads */ }
}

Scenario 8: Synchronized method throws an exception

When a synchronized method exits abruptly due to an exception, the JVM automatically releases the lock, allowing other threads to acquire it without deadlock.

Conclusion: The lock is released on normal exit or exception, so the scenario remains thread‑safe.

public class Condition7 implements Runnable {
    private static Condition7 instance = new Condition7();
    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) method0(); // throws
        if (Thread.currentThread().getName().equals("Thread-1")) method1(); // normal
    }
    private synchronized void method0() { /* ... */ throw new RuntimeException(); }
    private synchronized void method1() { /* ... */ }
    public static void main(String[] args) { /* start two threads */ }
}

Summary

The article systematically demonstrates the behavior of the synchronized keyword in eight typical Java multithreading scenarios, explains the lock objects involved (object lock, class lock, re‑entrancy), and provides clear conclusions on thread‑safety, which are essential knowledge for Java developers and interview preparation.

Source: blog.csdn.net/x541211190/article/details/106272922

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.

JavamultithreadingLocksynchronized
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.