为什么我的输入显示一个线程在另一个线程之后执行,而不是同时?

时间:2014-06-22 06:35:54

标签: java multithreading

我研究了一个线程的概念,并看到它是让代码同时在两个进程中运行。继承了我的代码

public class Connor extends Thread{

    public void run() {
        for(int i=0; i< 10; i ++){
            System.out.println("Hello " + i);
    }

    public static void main(String[] args){
        Connor runner1 = new Connor();
        Connor runner2 = new Connor();
        runner1.start();
        runner2.start();
    }
}

我的输出http://imgur.com/yAZqgal

似乎两个线程同时启动(单独的进程,由两个前导0指示)但是一个执行(1-9)然后另一个执行(1-9)。他们还假设交织(1,1,2,2,...)bc线程都打印到控制台。我研究并发现start是正确的方法,因为它告诉线程类在另一个线程中执行run方法?任何人都可以解释为什么我得到这个输出?

4 个答案:

答案 0 :(得分:5)

假设你有十个差事你需要做,而你的妹妹有十个差事她需要做,而你只有一辆车。你是否在每次差事后将车开回来并切换司机?当然不是。这将是荒谬的低效率。每个线程基本上只需要输出流。所以将它们紧密交错是荒谬的。

答案 1 :(得分:3)

您的代码看起来很好。我猜你的线程并不是因为它们以快速终止而并行运行。将循环限制从10更改为1000,您将看到效果。

启动线程本身操作比较繁重。您的代码启动第一个线程,然后启动第二个线程。第一个线程在第二个线程有机会开始执行其业务逻辑之前终止。

答案 2 :(得分:2)

在多线程的情况下,无法保证哪个线程被分配给处理器运行的时间,在这种情况下,结果是不可预测的,并且每次运行都会产生不同的输出。

如果您正在寻找所需的输出,那么您需要同步块。使用waitnotify即可轻松实现。

请直接从 Oracle官方网站查看下面的课程:

注意: wait&amp;必须在notify块内调用synchronized,并且可以调用与其同步的同一对象。

示例代码:(读取内联注释

public class Connor extends Thread {

    private static Connor runner1 = new Connor();
    private static Connor runner2 = new Connor();

    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Hello " + i);

            // wake up another thread to come out from wait state
            if (runner1 == this) {
                // wake up runner2
                synchronized (runner2) {
                    runner2.notify();
                }
            } else {
                // wake up runner1
                synchronized (runner1) {
                    runner1.notify();
                }
            }

            synchronized (this) {
                try {
                    // say current thread to wait until notify by another thread
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        runner1.start();
        runner2.start();
    }
}

输出:

Hello 0
Hello 0
Hello 1
Hello 1
Hello 2
Hello 2
Hello 3
Hello 3
Hello 4
Hello 4
Hello 5
Hello 5
Hello 6
Hello 6
Hello 7
Hello 7
Hello 8
Hello 8
Hello 9
Hello 9

答案 3 :(得分:0)

  

为什么我的输入显示一个线程在另一个线程之后执行,而不是同时执行?

一般的解释是线程调度是不可预测的。交错可能发生......或者可能不会。这是Java线程的基础。 (实际上是用大多数其他语言进行线程化。)

如果你需要线程执行以完全可预测的方式交错,你需要实现某种类型的握手机制,其中一个线程等待另一个线程做某事,并继续。但这很复杂,通常会破坏使用线程的目的。

FWIW:@ Braj的答案显示了如何实现严格的交错。但请注意,这实际上意味着一次只能执行一个线程。此外,等待/通知将导致线程调度程序的大量工作...一些应用程序运行速度明显慢于您刚刚在一个线程上完成工作。


在这个特定的例子中,有两个问题相结合,使得任何短期交错都不可能:

  1. 在Java中创建新的本机线程相对昂贵,因为它通常需要从OS请求内存块来容纳线程堆栈。这反过来又需要OS&#34;搞乱&#34;使用页表,将内存块清零等等。

  2. 本机线程调度由操作系统实现,并且在相当粗粒度的级别上运行...因为从典型应用程序的角度来看,这是最有效的操作方式。 (切换线程&#34;上下文&#34;在PC级机器中是相对昂贵的操作,并且线程调度程序本身可能有工作要做。)

  3. 在你的例子中,第一个线程可能会说&#34;你好&#34;在第二个线程准备好安排之前十次。