为什么线程执行会提供不同的输出?
我试图在线程(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总是以及为什么在其他情况下存在随机行为?
这恰恰是Java中multithreading的行为, 不可预测 。
for(Thread t : threadArray){ //[Line of intrest]System.out.println("Starting Thread "+t.getName());
上面的一行在主线程中运行 – >所以输出总是按顺序排列(尽管其他输出行可以介于两者之间)
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.
注意: 启动Thread Thread-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
线程交织不是随机的 (在均匀随机数生成器的意义上),但是不可预测 。
在这种特殊情况下,如果主线程打印,则顺序执行可能是由写入System.out的所有涉及的线程引起的,其方法是同步的。 因此,在任何给定时间只有一个线程可以写入控制台(这就是为什么我们看到行而不是单个字符的交错),而其他想要打印的线程在队列中等待,直到另一个线程退出监视器。 显然,您使用的JVM实现确保线程以与进入该队列相同的顺序进入监视器,这是工作线程中的第一个操作,在它们启动后很快发生,因此以相同的顺序。
换句话说,在这个特定的程序中,在这个特定的JVM实现上,在这个操作系统上的重锁争用导致线程以高概率以特定顺序执行。 在其他JVM实现,其他操作系统,甚至是略微修改的程序上,行为可能完全不同。 因此,即使您的测试从未观察到不同的顺序,您也不应该假设特定的顺序。
这是因为无法保证线程在您的情况下启动后立即运行。 你必须明确地同步它。
看看为什么在java中的线程对象上调用start()时不会立即调用run()
有时线程可以产生不同的输出。 这是因为我们不知道哪个线程正在哪个时刻运行。 它基于JVM,因此无法预测。