我从答案中获取代码-https://stackoverflow.com/a/9286697/2674303
为什么我创建了当前主题,而我不明白为什么该代码会导致死锁:
public class Lock implements Runnable {
static {
System.out.println(Thread.currentThread().getId() + "# Getting ready to greet the world");
try {
System.out.println(Thread.currentThread().getId() + "# before lock creation");
Lock target = new Lock();
System.out.println(Thread.currentThread().getId() + "# after lock creation");
Thread t = new Thread(target);
t.start();
System.out.println(Thread.currentThread().getId() + "# awaiting thread finish");
t.join();
System.out.println(Thread.currentThread().getId() + "# static block finished");
} catch (InterruptedException ex) {
System.out.println("won't see me");
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread() + "Hello World! ");
}
public void run() {
System.out.println(Thread.currentThread().getId() + "# Started thread");
Thread t = new Thread(new Lock());
t.start();
}
}
我试图启动它很多时间,并且总是导致死锁。
输出始终相同:
1# Getting ready to greet the world
1# before lock creation
1# after lock creation
1# awaiting thread finish
13# Started thread
我试图使初始化程序变为非静态,并且在此之后代码不会导致死锁。因此,我认为它与静态类初始化有关。
你能解释一下吗?
感谢John Skeet的回答,但为简化起见,我删除了代码行,这使我无法理解该示例:
public class Lock implements Runnable {
static {
try {
Thread thread = new Thread(new Lock());
thread.start();
thread.join();
} catch (InterruptedException ex) {
System.out.println("won't see me");
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread() + "Hello World! ");
}
public void run() {
new Lock();
}
}
它也导致死锁
答案 0 :(得分:8)
新线程正在尝试在run
类内调用Lock
。该方法本身尝试创建Lock
的新实例。在完成Lock
类的初始化之前,它不能执行 1 。 JVM知道另一个线程已经在初始化该类,因此它将阻塞直到初始化完成。
不幸的是,由于run
的调用,初始化工作要等到t.join()
完成之后才能完成。因此,这两个线程中的每个线程都需要对方取得进展才能执行任何操作-死锁。
正是出于这个原因,绝对值得避免在类初始化程序中做很多工作。
即使run()
方法本身为空,也都会发生这种情况。但这比那更糟-因为run()
方法要等到它创建另一个线程并等待那个线程完成调用run()
时才能完成,等等。这是另一个原因失败-它基本上会生成线程,直到JVM耗尽资源为止。因此,即使删除类型初始值设定项也不会使您使用有效的代码。
关于为什么需要类型初始化的信息,请参见section 12.4.1 of the JLS:
类或接口类型T将在以下任何一种首次出现之前立即初始化:
- T是一个类,并创建T的实例。
- 调用T声明的静态方法。
- 分配了由T声明的静态字段。
- 使用由T声明的静态字段,并且该字段不是常量变量(第4.12.4节)。
表达式new Lock()
将始终要么初始化Lock
,要么等待初始化完成(当然可能已经发生了)。
1 如果在run
中拆分代码,以便创建Lock
的实例,然后登录,然后启动线程,您将看到它是创建的的Lock
处于封锁状态。