当前位置: 首页 > 面试题库 >

如果在静态初始化程序块中创建线程,程序将挂起

汝繁
2023-03-14
问题内容

我遇到了程序挂起的情况,看起来像死锁。但是我尝试用jconsole和visualvm来解决这个问题,但是他们没有发现任何死锁。样例代码:

public class StaticInitializer {

private static int state = 10;

static {
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            state = 11;
            System.out.println("Exit Thread");
        }
    });

    t1.start();

    try {
        t1.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("exiting static block");
}

public static void main(String...strings) {
    System.out.println(state);
}
}

当我在调试模式下执行此操作时,我可以看到控件达到@Override public void run(){state = 11;

但是一旦执行state =
11,它就会挂起/死锁。我在stackoverflow中查看了不同的帖子,我认为静态初始化程序是线程安全的,但在这种情况下,jconsole应该报告此情况。关于主线程,jconsole表示它处于等待状态,这很好。但是对于在静态初始化程序块中创建的线程,jconsole表示它处于RUNNABLE状态,没有被阻塞。我很困惑,这里缺少一些概念。请帮帮我。


问题答案:

您不仅在 启动 另一个线程-您还在 加入
它。该新线程必须等待StaticInitializer完全初始化才能继续,因为它正在尝试设置state字段…并且初始化已经在进行中,因此它等待。但是,它将永远等待,因为初始化正在等待该新线程终止。经典僵局。

有关类初始化涉及的细节,请参见Java语言规范第12.4.2节。重要的是,初始化线程将“拥有”监视器StaticInitializer.class,但
线程将等待获取该监视器。

换句话说,您的代码有点像这个非初始化代码(省略了异常处理)。

final Object foo = new Object();
synchronized (foo)
{
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (foo) {
                System.out.println("In the new thread!");
            }
        });
    t1.start();
    t1.join();
});

如果您能理解 代码为何会陷入僵局,那么您的代码基本上是相同的。

道德上不要在静态初始化程序中做很多工作。



 类似资料:
  • 问题内容: 我正在使用静态代码块来初始化我拥有的注册表中的某些控制器。因此,我的问题是,我可以保证在首次加载该类时,该静态代码块仅被绝对调用一次吗?我知道我不能保证何时将调用此代码块,我猜是在Classloader首次加载时。我意识到我可以在静态代码块中的类上进行同步,但是我猜这实际上是怎么回事? 简单的代码示例将是; 还是我应该这样做? 问题答案: 是的,Java静态初始化器是线程安全的(使用第

  • 问题内容: 我有一个静态util类,它对敏感数据进行一些字符串操作。在使用此类之前,我需要使用我喜欢存储在文件中的值(例如用户名/密码)初始化某些静态变量。 我不太熟悉Java 中文件的加载方式,尤其是在 Spring DI 容器之外。任何人都可以帮助我/如何做到这一点? 谢谢! 另外: 文件的精确位置是未知的,但是它将在类路径上。有点像 问题答案: 首先,从中获取要加载的属性。这可以来自多个位置

  • 问题内容: 如标题所示,两者之间到底有什么区别 和 除了结构以外,还有什么重要区别吗? 问题答案: 对于您的示例,没有区别。但是如您所见, 只能接受一个表达式来初始化变量。但是,在静态初始化器(JLS 8.7)中,可以执行任意数量的语句。例如,可以这样做: 对于您的示例,显然不需要这样做,但是变量的初始化可能不仅仅使用表达式,甚至可能包含许多语句,因此Java制作了静态初始化器。

  • 问题内容: 我试图基于初始化按需持有人习惯用法创建一个线程安全的单例类。这是我的代码 我的期望是以线程安全的方式初始化ExecutorService,并且那里只有一个实例(静态)。 这段代码是实现了这一目标-还是需要任何更改? 问题答案: 根据SEI 指南,您的方法很好。 但是,由于我们有枚举,因此可以使用枚举的简单方法: 而且,如果您想变得真正聪明,还可以定义枚举实现的接口。因为这样您以后可以

  • 问题内容: 假设一个项目包含几个类,每个类都有一个静态初始化程序块。这些块以什么顺序运行?我知道在一个类中,这样的块按照它们在代码中出现的顺序运行。我读过所有类都一样,但是我编写的一些示例代码对此表示不同。我使用以下代码: 并得到以下输出: START static - grandparent static - parent static - child instance - grandparen

  • 10.6.1.程序初始化 现在用户启动程序就会首先看到Timeline界面。但是用户必须先设置个人选项并启动Service,否则就没有消息显示。这很容易让人摸不着头脑。 一个解决方案是,在启动时检查用户的个人选项是否存在。若不存在,就跳到选项界面,并给用户一个提示,告诉她下一步该怎么做。 ... @Override protected void onCreate(Bundle savedInsta