簡體   English   中英

這種行為背后的原因是什么(線程)

[英]What is the reason behind this behaviour(Thread)

我正在研究線程,並決定在我的重點代碼行運行之前和之后添加一些額外的文本,以供參考。 我希望在開頭和結尾處獲得一個“額外文本”。 然而......這並沒有發生,當我運行它時,第二個“額外文本”剛剛出現在第四個 position 中。 我是初學者,需要知道為什么會這樣……

- -代碼 - -

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!

這是一個常見的並發錯誤。

程序的 main 方法在主線程上運行。 因此,在您啟動hiObjheyObj線程之前,您已經有了一個線程。 啟動兩個新線程后,您將擁有三個。 每個都同時執行。 這意味着每個線程都可以執行代碼而無需等待其他線程。 線程之間不保證順序。

這會導致您觀察到的行為。 hiObjheyObj啟動之前,在主線程上運行的 main 方法會打印"extra-text" 接下來,啟動 hiObj 和 heyObj。 主線程到達Thread.currentThead().sleep(10)行,這導致它暫停執行 10 毫秒。 在大多數機器(包括您的機器)上,這足以讓其他兩個線程開始執行。 每個線程在其run方法中開始for循環並打印"HI""HEY" 因此,output 的前三行是(不保證"HI""HEY"的順序):

"extra-text"

"HI"

"HEY"

接下來, hiObjheyObj線程到達Thread.sleep(500)行,這導致它們暫停執行 500 毫秒。 10 毫秒過去后,主線程將完成睡眠並恢復。 請注意, hiObjheyObj線程現在都不能恢復。 因此,打印的下一行將是main中執行的下一行。 這是"extra-text" 因此,預期的 output 是:

"extra-text"

"HI"

"HEY"

"extra-text"

在接下來的幾秒鍾內,來自hiObjheyObj線程的剩余打印將發生。 在 Java 中,只有在所有其他線程都退出后,主線程才會退出(除非調用System.exit或存在未捕獲的異常)。 在這種情況下,這意味着程序只有在main執行結束並且hiObjheyObj的 run 方法都返回時才會退出。

要更改程序以使最后一個"extra-text"始終打印在最后,您必須使主線程等待hiObjheyObj線程完成。 在 Java 中, Thead上有一個名為join的方法,它會導致調用線程等待直到加入的線程死亡。 在您的程序中,您可以將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"

如果你擺脫

Thread.currentThread().sleep(10);

在主方法中,您將看到您的兩個額外文本在執行后立即打印到控制台。 通過使用 sleep(10),您只需延遲第二個額外文本,同時您的 2 個線程打印它們的第一個 output。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM