gst*_*low 2 java concurrency multithreading deadlock static-initialization
我从那个答案中获取代码-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();
}
}
Run Code Online (Sandbox Code Playgroud)
我试图启动它很多时间,并且总是导致死锁。
输出始终相同:
1# Getting ready to greet the world
1# before lock creation
1# after lock creation
1# awaiting thread finish
13# Started thread
Run Code Online (Sandbox Code Playgroud)
我试图使初始化程序变为非静态,并且在此之后代码不会导致死锁。因此,我认为它与静态类初始化相关。
你能解释一下吗?
感谢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();
}
}
Run Code Online (Sandbox Code Playgroud)
也会导致僵局
新线程正在尝试run在Lock类中调用。该方法本身会尝试创建的新实例Lock。在类完成初始化之前,它不能执行1Lock。JVM知道另一个线程已经在初始化该类,因此它将阻塞直到初始化完成。
不幸的是,run由于t.join()调用的原因,初始化无法完成。因此,这两个线程中的每个线程都需要对方取得进展才能执行任何操作-死锁。
正是由于这个原因,绝对值得避免在类初始化程序中做很多工作。
即使该run()方法本身为空,也都会发生这种情况。但这比这更糟-因为该run()方法要等到创建另一个线程并等待该线程完成调用之后才能完成run(),所以这是失败的另一个原因-它基本上会生成线程,直到JVM耗尽资源为止。因此,即使删除类型初始值设定项也不会使您进入工作代码。
关于为什么需要类型初始化的原因,请参见JLS的12.4.1节:
类或接口类型T将在以下任何一种首次出现之前立即初始化:
- T是一个类,并创建T的实例。
- 调用由T声明的静态方法。
- 分配由T声明的静态字段。
- 使用由T声明的静态字段,并且该字段不是常量变量(第4.12.4节)。
该表达式new Lock()将始终是的初始化Lock,或者等待初始化完成(当然可能已经发生)。
1如果拆分了代码,run以便创建的实例,Lock然后登录,然后启动线程,则将看到它Lock是阻塞的创建。