为什么主线程没有唤醒?

Q10*_*ing 5 java multithreading jvm classloader

代码如下,在Main方法中我调用静态方法:

\n
public class Main {\n    public static void main(String[] args) {\n        MyFactory.getSomething();\n        System.out.println("over"); \n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在静态方法中,让主线程等待,然后由demo线程唤醒。但是主线程没有唤醒,我不知道为什么。

\n
import java.util.concurrent.TimeUnit;\n\npublic class MyFactory {\n    private static Object lock = new Object();\n\n    static{\n        init();\n    }\n\n    private static void init(){\n        new Thread(()->{\n            try {\n                // make this thread run after main thread\n                TimeUnit.SECONDS.sleep(3);\n                System.out.println("task run...");\n                synchronized (lock){\n                    lock.notifyAll();  // notify main thread\n                }\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        },"demo-thread").start();\n\n        synchronized (lock){\n            try {\n                System.out.println("waiting...");\n                lock.wait();  // wait\n                System.out.println("wake up");\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n    public static Object getSomething(){\n        return null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出如下:

\n
waiting...\n
Run Code Online (Sandbox Code Playgroud)\n

我的预期应该是这样的:

\n
waiting...\ntask run...\nwake up\nover\n
Run Code Online (Sandbox Code Playgroud)\n

这里是Github上的演示代码,您可以下载运行。

\n
\n

我的尝试

\n

task run...我看到有人说可能是死锁导致了问题。我不这么认为。因为我们在输出中看不到信息。所以demo thread根本没有获得锁。

\n

当我更改代码时MyFactory.java。(添加一个新线程来运行init方法)

\n

由此

\n
static{\n  init();\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

对此。

\n
static{\n  new Thread(()->init()).start();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

一切正常。程序不会阻塞。

\n

这是我更改代码后的输出。

\n
static{\n  new Thread(()->init()).start();\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

回到原来的问题“为什么主线程没有唤醒”\xef\xbc\x9f\n我认为JVM没有完全加载是MyFactory.class由于主线程阻塞\xe3\x80\x82我不知道我的猜测是否正确是对的???

\n
\n

m0s*_*it0 4

我不是 JVM 内部的专家,但我认为问题出在这里:

static {
    init();
}
Run Code Online (Sandbox Code Playgroud)

我怀疑这会在 JVM 类加载器加载类时执行。然而,这个类加载永远不会完成,因为您阻塞了类加载器本身,因此程序其余部分的执行将永远不会恢复,因此另一个线程永远不会启动。

如果删除静态块并直接调用它:

public static void main(String[] args) {
    // ...
    MyFactory.init();
    MyFactory.getSomething();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

您会看到它工作正常。

更多详情参见JLS 12.4.2

顺便说一句,睡眠并不是同步线程的好主意。