我试图在线程(Java)中测试/学习一些基本的东西,并遇到了一个简单但令人困惑的输出。以下是我的课程
public class CopyMaster implements Runnable{
@Override
public void run() {
System.out.println("Run called from Copy Master for thread "+Thread.currentThread().getName());
}
}
我调用线程的主类
public class Main {
public static void main(String[] args) {
Thread[] threadArray = new Thread[4];
for(int i=0; i<threadArray.length; i++){
threadArray[i] = new Thread(new CopyMaster());
}
for(Thread t : threadArray){
//[Line of intrest]System.out.println("Starting Thread "+t.getName());
t.start();
}
}
}
OP(未注释的兴趣点)
Starting Thread Thread-0
Starting Thread Thread-1
Run called from Copy Master for thread Thread-0
Starting Thread Thread-2
Run called from Copy Master for thread Thread-1
Starting Thread Thread-3
Run called from Copy Master for thread Thread-2
Run called from Copy Master for thread Thread-3
OP(有兴趣点评论)
Run called from Copy Master for thread Thread-2
Run called from Copy Master for thread Thread-3
Run called from Copy Master for thread Thread-0
Run called from Copy Master for thread Thread-1
我已尝试多次运行代码并观察到打印输出的顺序在感兴趣的注释行中是随机的,在未注释的行中是正确的(按顺序)......
为什么它会像那样?// EDITED因为这会让我感到困惑
编辑:
我理解线程的行为是不可预测的,但我的主要问题是为什么它在一个案例中保持oredr总是以及为什么在其他情况下存在随机行为?
答案 0 :(得分:2)
这正是Java中多线程的行为,不可预测的。
for(Thread t : threadArray){
//[Line of intrest]System.out.println("Starting Thread "+t.getName());
以上行在主线程中运行 - &gt;所以输出总是按顺序排列(尽管其他输出行可以介于其间)
t.start();
上面的行启动每个线程(准备线程执行,但可能不会立即调用run方法)。没有人能够预测哪个线程run()
将首先执行。它完全留给JVM和底层操作系统。
}
如果您希望输出有序,请使用join()
等待其他线程终止。
编辑:
OP(未注释的兴趣点)
Starting Thread Thread-0 --> executed in main thread --> 0--> in order
Starting Thread Thread-1 --> main thread --> 1 --> in order
Run called from Copy Master for thread Thread-0 --> executed in thread-0.
Starting Thread Thread-2 --> executed in main. --> 2 -> in order
Run called from Copy Master for thread Thread-1 --> executed in thread-1
Starting Thread Thread-3 --> main --> 3 --> in order
Run called from Copy Master for thread Thread-2 -->executed in thread-2.
Run called from Copy Master for thread Thread-3 --> executed in thread-3.
注意: 启动线程-0 将打印在主线程中。因此,下一行thread.start()
可能甚至没有被执行过。日志误导。
以下几行实际上表明了线程是如何运行的。这些日志没有误导性。
OP(有兴趣点评论)
Run called from Copy Master for thread Thread-2
Run called from Copy Master for thread Thread-3
Run called from Copy Master for thread Thread-0
Run called from Copy Master for thread Thread-1
答案 1 :(得分:1)
线程交错不是 random (在统一随机数生成器的意义上),但是不可预测的。
在这种特殊情况下,主线程打印时的顺序执行可能是由写入System.out的所有涉及线程引起的,其方法是同步的。因此,在任何给定时间只有一个线程可以写入控制台(这就是为什么我们看到行而不是单个字符的交错),而其他想要打印的线程在队列中等待,直到另一个线程退出监视器。显然,您使用的JVM实现确保线程以与进入该队列相同的顺序进入监视器,这是工作线程中的第一个操作,在它们启动后很快就会发生,因此顺序相同。 / p>
换句话说,在此特定程序中,此操作系统上此特定JVM实现上的重锁争用会导致线程以特定顺序执行的概率很高。在其他JVM实现,其他操作系统,甚至是略微修改的程序上,行为可能完全不同。因此,即使您的测试从未观察到不同的顺序,您也不应该假定特定的顺序。
答案 2 :(得分:0)
因为无法保证线程在你的情况下启动后立即运行。你必须明确地同步它。
看看 Why is run() not immediately called when start() called on a thread object in java
答案 3 :(得分:0)
有时线程会产生不同的输出。这是因为我们不知道哪个线程正在哪个时刻运行。它基于JVM,因此无法预测。