首页 > 解决方案 > 这种行为背后的原因是什么(线程)

问题描述

我正在研究线程,并决定在我的重点代码行运行之前和之后添加一些额外的文本,以供参考。我希望在开头和结尾处获得一个“额外文本”。然而......这并没有发生,当我运行它时,第二个“额外文本”刚刚出现在第四个位置。我是初学者,需要知道为什么会这样……

- -代码 - -

class Hi extends Thread{

    public void run(){
        for(int i=1; i<=5; i++){
            System.out.println("HI!");
            try{
                Thread.sleep(500);
            } catch(InterruptedException e){}

        }
    }

}


class Hey extends Thread{
    public void run(){
        for(int i=1; i<=5; i++){
            System.out.println("HEY!");
            try{
                Thread.sleep(500);
            } catch(InterruptedException e){}

        }
    }

}

public class MyClass {

    public static void main(String[] args){

        Hi hiObj = new Hi();
        Hey heyObj = new Hey();

        System.out.println("extra-text");

        hiObj.start();
        heyObj.start();

        try {
            Thread.currentThread().sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("extra-text");

    }



}

- -输出 - -

extra-text
HI!
HEY!
extra-text
HEY!
HI!
HEY!
HI!
HEY!
HI!
HEY!
HI!

标签: javamultithreadingthread-sleep

解决方案


这是一个常见的并发错误。

程序的 main 方法在主线程上运行。因此,在您启动hiObjandheyObj线程之前,您已经拥有了一个线程。启动两个新线程后,您将拥有三个。每个都同时执行。这意味着每个线程都可以执行代码而无需等待其他线程。线程之间不保证顺序。

这会导致您观察到的行为。在启动hiObjheyObj启动之前,在主线程上运行的 main 方法会打印"extra-text". 接下来,启动 hiObj 和 heyObj。主线程到达Thread.currentThead().sleep(10)导致它暂停执行 10 毫秒的行。在大多数机器(包括您的机器)上,这足以让其他两个线程开始执行。每个线程for在其方法中开始循环run并打印"HI""HEY"。因此,输出的前三行是(不保证"HI"和的顺序):"HEY"

"extra-text"

"HI"

"HEY"

接下来,hiObjandheyObj线程到达Thread.sleep(500)导致它们暂停执行 500 毫秒的行。10 毫秒过去后,主线程将完成睡眠并恢复。请注意,此时hiObjheyObj线程都无法恢复。因此,打印的下一行将是在 中执行的下一行main。这是"extra-text". 因此,预期的输出是:

"extra-text"

"HI"

"HEY"

"extra-text"

在接下来的几秒钟内,将出现来自hiObjheyObj线程的剩余打印。在 Java 中,只有在所有其他线程都退出后,主线程才会退出(除非System.exit被调用或存在未捕获的异常)。main在这种情况下,这意味着程序只有在执行结束并且hiObj' 和heyObj' 的 run 方法都返回时才会退出。

要更改程序以使最后一个"extra-text"始终打印在最后,您必须使主线程等待hiObjheyObj线程完成。在 Java 中,有一个方法 on Theadcalledjoin会导致调用线程等待,直到加入的线程死亡。在您的程序中,您可以修改MyClass为如下所示:

public class MyClass {

    public static void main(String[] args){

        Hi hiObj = new Hi();
        Hey heyObj = new Hey();

        System.out.println("extra-text");

        hiObj.start();
        heyObj.start();

        try {
            Thread.currentThread().sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        hiObj.join();
        heyObj.join();

        System.out.println("extra-text");

    }

}

通过此更改,main将首先等待hiObj完成,然后等待完成,然后再heyObj打印"extra-text"


推荐阅读