如果在静态初始化程序块中创建了线程,程序将挂起 [英] Program hangs if thread is created in static initializer block

查看:117
本文介绍了如果在静态初始化程序块中创建了线程,程序将挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到过我的程序挂起的情况,看起来像死锁。但我试着用jconsole和visualvm搞清楚,但他们没有发现任何死锁。示例代码:

I have come across a situation where my program hangs, looks like deadlock. But I tried figuring it out with jconsole and visualvm, but they didn't detect any deadlock. Sample code:

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;

When I execute this in debug mode then I could see control reaching @Override public void run() { state = 11;

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

but as soon as state=11 is executed it just hangs/deadlocks. I looked in different postings in stackoverflow and I thought that static initializers are thread-safe but in that case jconsole should report this. About main thread, jconsole saying that it is in waiting state, and that's fine. But for the thread created in static initializer block, jconsole says that it is in RUNNABLE state and not blocked. I am confused and here lacking some concept. Please help me out.

推荐答案

你不只是开始另一个线程 - 你是加入就可以了。新线程必须等待 StaticInitializer 才能完全初始化,然后才能继续,因为它正在尝试设置状态 field ...并且初始化已经在进行中,所以它等待。但是,它将永远等待,因为初始化正在等待新线程终止。经典死锁。

You're not just starting another thread - you're joining on it. That new thread has to wait for StaticInitializer to be fully initialized before it can proceed, because it's trying to set the state field... and initialization is already in progress, so it waits. However, it's going to be waiting forever, because that initialization is waiting for that new thread to terminate. Classic deadlock.

参见 Java语言规范部分12.4.2 ,了解有关类初始化的内容的详细信息。重要的是,初始化线程将拥有 StaticInitializer.class 的监视器,但 new 线程将等待获取该监视器。

See the Java Language Specification section 12.4.2 for details about what's involved in class initialization. Importantly, the initializing thread will "own" the monitor for StaticInitializer.class, but the new thread will be waiting to acquire that monitor.

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

In other words, your code is a bit like this non-initializer code (exception handling elided).

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();
});

如果你能理解为什么那个代码会死锁,它基本上是一样的对于你的代码。

If you can understand why that code would deadlock, it's basically the same for your code.

道德并不是在静态初始化器中做太多工作。

The moral is not to do much work in static initializers.

这篇关于如果在静态初始化程序块中创建了线程,程序将挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆