我遇到过程序挂起的情况,看起来像是死锁。但我尝试用 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);
}
}
当我在 Debug模式下执行它时,我可以看到控制到达 @覆盖 公共(public)无效运行(){ 状态 = 11;
但是一旦执行 state=11,它就会挂起/死锁。我查看了 stackoverflow 中的不同帖子,我认为静态初始化程序是线程安全的,但在那种情况下,jconsole 应该报告这一点。关于主线程,jconsole 说它处于等待状态,这很好。但是对于在静态初始化 block 中创建的线程,jconsole 表示它处于 RUNNABLE 状态并且没有被阻塞。我很困惑,这里缺乏一些概念。请帮帮我。
最佳答案
您不只是开始另一个线程 - 您正在加入它。新线程必须等待 StaticInitializer
完全初始化才能继续,因为它正在尝试设置 state
字段...并且初始化已经在进行中,所以它等待。但是,它将永远等待,因为初始化正在等待新线程终止。经典死锁。
参见 Java Language Specification section 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();
});
如果您能理解为什么代码会死锁,那么您的代码基本上是一样的。
道德是不要在静态初始化器中做太多工作。
关于java - 如果在静态初始化 block 中创建线程,程序将挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43841656/