【问题标题】:Why Thread execution is giving different output?为什么线程执行给出不同的输出?
【发布时间】:2014-07-31 04:48:15
【问题描述】:

我试图测试/学习线程(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

我已尝试多次运行代码并观察到打印输出的顺序在感兴趣的注释行中是随机的,而在未注释的行中是随机的(按顺序)...

为什么会这样?//已编辑,因为这混淆了我的意思

编辑:

我知道线程的行为不可预测,但我的主要问题是为什么它在一种情况下始终保持 oredr 以及为什么在另一种情况下存在随机行为?

【问题讨论】:

  • 为什么你认为应该按顺序排列?
  • 再运行几次。
  • @SotiriosDelimanolis - 我认为他需要在进行任何编码之前阅读并发基础知识。 VD',请阅读 - docs.oracle.com/javase/tutorial/essential/concurrency
  • 主线程按顺序执行,其他线程在哪里并行运行,并行执行总是不可预测的。
  • 两者都应该是随机的。但是当您取消注释 System.out 语句时,执行需要一些 CPU 时间。前一个线程很可能完成执行,而下一个线程是调度程序的唯一选择。我认为这就是为什么它看起来是按顺序排列的。如果你增加线程数你可能会看到序列的变化,或者你可以在run()方法中添加一个sleep语句来检查它。

标签: java multithreading


【解决方案1】:

这正是Java中多线程的行为,不可预测

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.

注意: Starting Thread Thread-0 打印在 main 线程中。因此,下一行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

【讨论】:

  • 同意,我也理解,但我的问题是兴趣线未注释为什么它遵循顺序??
  • @VD' - 尝试让每个线程在注释行之前休眠。运行这段代码几次,告诉我们你看到了什么。
  • @VD' - 不。即使您评论感兴趣的行,也没有任何区别。差异线在 主线程 中运行(请参阅我的答案)。在已注释和未注释的情况下,run() 方法都会乱序执行。
  • @TheLostMind 如果我不理解您的答案,请纠正我,但您的意思是说主线程中运行的任何内容都是连续的,但是 CopyMaster 中的其他语句有时应该是不按顺序的。我试过了很多时间,但它们也在seq中
  • 接受你的回答,你和 naveejr(有问题的 cmets)帮助我理解了这一点。事情就像你说的主线程总是 seq 但其他可以是随机的,我验证了增加线程数组大小
【解决方案2】:

线程交织不是随机(在统一随机数生成器的意义上),而是不可预测

在这种特殊情况下,如果主线程打印,则顺序执行可能是由所有相关线程写入 System.out 引起的,其方法是同步的。因此,在任何给定时间,只有一个线程可以写入控制台(这就是为什么我们看到交错的行而不是单个字符的原因),而其他想要打印的线程在队列中等待,直到另一个线程退出监视器。显然,您使用的 JVM 实现确保线程以与进入该队列的顺序相同的顺序进入监视器,这是工作线程中的第一个操作,在它们启动后很快发生,因此以相同的顺序。

换句话说,在这个特定的程序中,在这个特定的 JVM 实现上,在这个操作系统上,严重的锁争用导致线程很有可能以特定的顺序执行。在其他 JVM 实现、其他操作系统,甚至稍微修改过的程序上,行为可能完全不同。因此,您不应该假设特定的顺序,即使您的测试从未观察到不同的顺序。

【讨论】:

  • +1 投资答案。这是否意味着主线程有时也可能是不可预测的并且可以提供非顺序输出??
【解决方案3】:

这是因为在您的情况下,无法保证线程在启动后立即运行。你必须明确地同步它。

看看 Why is run() not immediately called when start() called on a thread object in java

【讨论】:

  • 这是因为在 //[Line of intrest]System.out.println("Starting Thread "+t.getName()); 中完成了一些工作我不会相信这种行为。把它放在一个循环中,看看你感兴趣的线是否真的很有趣。 :-)
【解决方案4】:

有时线程可以产生不同的输出。这是因为我们不知道哪个线程在哪个时刻运行。它基于JVM,因此无法预测。

【讨论】:

    猜你喜欢
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多