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

主线程无法唤醒?Java静态代码块线程同步问题排查

主线程在静态代码块中wait后无法被唤醒的原因分析

问题重现

调用静态方法时,静态代码块内的主线程进入wait状态后,始终无法被预期的线程唤醒,相关代码如下:

Main类代码

public class Main {
    public static void main(String[] args) {
        MyFactory.getSomething();
        System.out.println("over"); 
    }
}

MyFactory类代码

import java.util.concurrent.TimeUnit;

public class MyFactory {
    private static Object lock = new Object();

    static{
        init();
    }

    private static void init(){
        new Thread(()->{
            try {
                // 让该线程晚于主线程执行
                TimeUnit.SECONDS.sleep(3);
                System.out.println("task run...");
                synchronized (lock){
                    lock.notifyAll();  // 唤醒主线程
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"demo-thread").start();

        synchronized (lock){
            try {
                System.out.println("waiting...");
                lock.wait();  // 进入等待
                System.out.println("wake up");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static Object getSomething(){
        return null;
    }
}

实际输出

waiting...

预期输出

waiting...
task run...
wake up
over

尝试的解决方法

将静态代码块中直接调用init()的逻辑,改为在新线程中执行init():

  • 原代码:
    static{
      init();
    }
    
  • 修改后代码:
    static{
      new Thread(()->init()).start();
    }
    

修改后程序正常运行,输出如下:

over
waiting...
task run...
wake up

问题核心原因

你的猜测完全正确,问题根源是主线程阻塞导致MyFactory类的初始化未完成,具体逻辑链如下:

  1. 主线程执行MyFactory.getSomething()时,触发MyFactory类的加载初始化流程,此时主线程会持有MyFactory.class的类初始化锁,直到类初始化(静态代码块执行完毕)完成才会释放。
  2. 静态代码块调用init(),先启动demo-thread,随后主线程获取lock锁并进入wait状态(此时会释放lock锁,但不会释放MyFactory.class的初始化锁)。
  3. demo-thread启动后,在执行synchronized (lock)之前需要访问MyFactory的静态变量lock,但此时MyFactory类还处于初始化未完成状态(主线程卡在init()的wait处,静态代码块没执行完),demo-thread会被阻塞在类初始化的等待队列中,根本无法走到获取lock锁并执行notifyAll的步骤。
  4. 最终主线程无法被唤醒,demo-thread也无法继续执行,程序陷入永久阻塞。

而修改为在新线程中执行init()后,主线程会快速完成MyFactory的类初始化(静态代码块仅启动线程就结束),释放类初始化锁,后续所有线程都能正常访问类成员,因此程序可以正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:35:11