当我们有多个Java线程时,运行时会发生什么?
我试图了解当您有多个线程对象并在它们上调用 start 时会发生什么。
为此,我编写了以下代码:
public class Testing {
public static void main(String[] args) {
for(int i =0; i <100; i++){
(new TestThread()).start();
}
}
}
class TestThread extends Thread {
@Override
public void run() {
System.out.println("Thread instance: " + Thread.currentThread().getName());
}
}
所以我得到的输出涉及 Thread-x,其中 x 从 0 到 99,但它们的顺序与自然顺序不同(即 0,1,2,3,...)。我预料到了这一点,因为我读到我们无法控制这些线程运行时会发生什么,但我想要求澄清运行时究竟发生了什么。
是不是主线程经历了所有 100 次 for 循环的迭代创建这些线程,然后 JVM 稍后任意决定这些 Thread 对象中的每一个何时启动?
谢谢。
回答
我想要求澄清运行时究竟发生了什么。
实际发生的情况是,当您调用 时start(),JVM通常会1向操作系统发出系统调用以执行以下操作:
-
为新线程堆栈分配内存段。(通常分配两个段:一个段用于线程堆栈,第二个只读段用于检测堆栈溢出。)
-
创建一个新的本地线程2。
创建本机线程时,它必须等待(与所有其他当前准备运行的线程一起)等待操作系统的线程调度程序将其调度到物理内核。一般来说,操作系统的线程调度器尊重优先级,但相同优先级的线程之间的调度通常是不“公平的”;即不能保证“先到先得”。
因此,在某些时候,操作系统将安排新的本机线程运行。当这种情况发生时,线程将执行一些获取Runnable引用并调用其run()方法的本机代码。相同的代码将处理run()方法中任何未捕获的异常。
确切的细节将是特定于 JVM 和特定于操作系统的,您实际上并不需要了解他们。
是不是主线程经历了所有 100 次 for 循环的迭代创建这些线程,然后 JVM 稍后任意决定这些 Thread 对象中的每一个何时启动?
不必要。它可能会,也可能不会。
实际发生的情况取决于操作系统的本机代码调度程序如何处理新创建的本机线程。这将取决于难以预测的各种因素。例如,其他线程和其他应用程序的行为等等。
基本上,不能保证3子线程将以任何特定顺序开始执行,或者主线程将或不会在任何子线程启动之前完成循环。
1 - 这对于在 Java 线程和本机线程之间提供 1 对 1 映射的 JVM 来说是典型的。这是当前大多数 JVM 的行为方式,但它不是唯一的实现模型。
2 - 本机线程是操作系统支持的线程。有关更多信息,请参阅Java 线程模型,有关示例,请参阅本机 POSIX 线程库。
3 - 在某些平台和负载条件下,您可能能够观察到行为模式,但您可能会发现行为在其他平台上有所不同等。