You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程疑问:synchronized块执行后线程调度顺序问题

Why does the unsynchronized println always run right after the synchronized block in my threaded Java code?

Let's break down what's happening with your code and why you're seeing that consistent output instead of the mixed order you expected.

First, here's your code for reference:

public class Callme {
    public Callme() {
        // TODO Auto-generated constructor stub
    }
    void callA(String msg) throws InterruptedException {
        synchronized (this) {
            System.out.print("["+msg);
            Thread.sleep(1000);
        }
        System.out.println("]");
    }
    void callB(String msg) throws InterruptedException {
        synchronized (this) {
            System.out.print("{"+msg);
            Thread.sleep(1000);
        }
        System.out.println("}");
    }
    void callC(String msg) throws InterruptedException {
        synchronized (this) {
            System.out.print("("+msg);
            Thread.sleep(1000);
        }
        System.out.println(")");
    }
}

public class Caller implements Runnable {
    public char msg;
    public Callme target;
    public Thread t;
    public Caller(char msg, Callme target) {
        this.msg = msg;
        this.target = target;
        t= new Thread(this);
    }
    @Override
    public void run() {
        try {
            switch (msg) {
                case '[':
                    target.callA("Hello");
                    break;
                case '{':
                    target.callB("Hello");
                    break;
                case '(':
                    target.callC("Hello");
                    break;
                default:
                    break;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// Execution code
Callme target = new Callme();
Caller ob1 = new Caller('[', target);
Caller ob2 = new Caller('{', target);
Caller ob3 = new Caller('(', target);
ob1.t.start();
ob2.t.start();
ob3.t.start();

The Core Issue: Thread Scheduling Optimizations

You’re right that your expected output (like [Hello(Hello] ) {Hello}) is theoretically possible, but in practice, the JVM and operating system’s thread scheduling makes this outcome extremely unlikely. Here’s why:

  • When a thread exits a synchronized block, it releases the lock on this—but it doesn’t immediately give up the CPU. Operating systems try to minimize context switches (the process of switching between threads) because they’re computationally expensive. The thread that just finished the synchronized block is already "warm" (loaded into the CPU’s cache), so the OS will almost always let it continue executing the remaining unsynchronized code (the println("]")) before waking up and scheduling another waiting thread.
  • The other threads (ob2 and ob3) are waiting to acquire the lock, but even after the lock is released, there’s a tiny delay while the scheduler wakes them up and switches context. In that split second, the original thread has already printed the closing bracket.

How to See Your Expected Output

If you want to force a context switch to trigger the mixed output you’re expecting, add a Thread.yield() call right after the synchronized block in each callX method. This tells the scheduler that the current thread is willing to give up its CPU time:

void callA(String msg) throws InterruptedException {
    synchronized (this) {
        System.out.print("["+msg);
        Thread.sleep(1000);
    }
    Thread.yield(); // Voluntarily give up CPU time
    System.out.println("]");
}

With this change, you’ll start seeing outputs like [Hello(Hello] ) {Hello} much more frequently, as the yield gives waiting threads a chance to acquire the lock and run their synchronized blocks before the first thread prints its closing bracket.

Final Note

Remember that thread scheduling is inherently non-deterministic. Your original code could produce the mixed output under rare circumstances (like if the OS interrupted the thread immediately after releasing the lock), but it’s not behavior you can rely on. The consistent output you’re seeing is just the OS optimizing for performance by avoiding unnecessary context switches.

内容的提问来源于stack exchange,提问作者Chaitanya Chavali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:10:38