我不擅长多线程,并对此代码感到困惑:
public class Main {
public static void main(String... args) throws Exception {
new Thread(Main::test).start();
}
private static synchronized void test() {
new Thread(Main::test).start();
System.out.println("TEST");
}
}
它会导致死锁吗?如果是这样,那为什么我无法让它陷入僵局?我的想法是,线程1获取对test()
的锁定,然后在test()
中创建的另一个线程试图获取它并且它们应该在彼此等待。但他们不是,为什么不呢?
我知道,在join()
中添加test()
会导致死锁,但是下面的示例为什么不使用连接和死锁?
每次运行时,此代码都会导致死锁:
public class Main {
public static void main(String... args) {
new Thread(Main::test).start();
new Thread(Main::test2).start();
}
private static void test() {
synchronized (Integer.class) {
try {
Thread.sleep(1);
} catch (Exception e) {
}
synchronized (Float.class) {
System.out.println("Acquired float");
}
}
}
private static void test2() {
synchronized (Float.class) {
try {
Thread.sleep(1);
} catch (Exception e) {
}
synchronized (Integer.class) {
System.out.println("Acquired integer");
}
}
}
}
不,第一个示例中的代码不能死锁。新启动的线程将一直等到前一个线程退出方法以获取锁定。
第二个示例中的代码死锁,因为锁是以相反的顺序获取的,并且由于睡眠可靠地相互阻塞。
当您处于初次学习如何考虑并发性和相关问题的阶段时,我非常建议使用物理道具来保持您的想法和假设清晰明确。
例如,抓住一张A3纸,设置一个“赛道”,你可以使用Monopoly片段来表示你在代码中做了什么,你期望发生什么,以及你的实验显示实际发生了什么。
当您的实验无法解决时,请先从一小部分开始,然后进行验证。然后再添加一些,依此类推。
如果您了解实际计算机(不是CS理想计算机或概念计算机)当前的工作原理,它会有所帮助。 CPU如何将数据从主内存中取出到其缓存中。两个或三个CPU如何决定哪一个CPU可以一次处理一个缓存行中的数据。然后,Java内存模型如何需要您编写源代码,以便JVM知道您实际意味着发生什么。