中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java線程中的start方法和run方法怎么使用

發布時間:2022-07-29 17:42:49 來源:億速云 閱讀:180 作者:iii 欄目:開發技術

本篇內容介紹了“Java線程中的start方法和run方法怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    start方法和run方法

    $start()$方法用來啟動一個線程,這時此線程處于就緒(可運行)狀態,并沒有運行,一旦得到$cpu$時間片,就開始執行$run()$方法。而直接調用$run()$方法,僅僅只是調用了一個類里的方法,其本質上還是在當前線程中執行的,因此只有使用$start()$方法來調用$run()$方法才能實現真正的多線程。

    示例代碼

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.run();
        }
    }

    上述代碼是直接調用的$run()$方法。可以看到打印信息里,是$main$線程執行了這個方法。

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.start();
        }
    }

    而如果使用$start()$方法啟動,才是真正的由$t1$線程執行的$run$方法。

    注意

    需要注意的是,當$Thread$對象調用了$start()$方法后,就會進入就緒狀態,處于就緒狀態時無法再調用$start()$方法,否則就會拋出$IllegalThreadStateException$異常,如下代碼所示

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.start();
            t1.start();
        }
    }

    異常信息:

    Java線程中的start方法和run方法怎么使用

    sleep方法與yield方法

    sleep

    • 調用$sleep()$方法會讓當前線程從$Running$狀態變成$Time Waiting$狀態(阻塞)

    • 其它線程可以使用$interrupt$方法打斷正在睡眠的線程,此時$sleep$方法會拋出InterruptedException

    • 睡眠結束后的線程未必會立刻得到執行

    • 建議用$TimeUnit$的$sleep$代替$Thread$的$sleep$來獲得更好的可讀性示例代碼

    @Slf4j(topic = "c.Test5")
    public class Test5 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            t1.start();
            log.debug("t1 state {}", t1.getState());
            //讓主線程休眠500ms
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("t1 state {}", t1.getState());
        }
    }
    //17:13:21.729 [main] DEBUG c.Test5 - t1 state RUNNABLE
    //17:13:22.245 [main] DEBUG c.Test5 - t1 state TIMED_WAITING

    上述代碼中,首先啟動$t1$線程,此時打印線程的狀態應該是處于$RUNNABLE$狀態,而讓主線程休眠是防止主線程先執行打印,但是還未進入到$sleep()$狀態。當執行到$run()$里邊的$sleep$方法時,線程進入$TIMED WAITING$狀態

    @Slf4j(topic = "c.Test6")
    public class Thread6 {
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread("t1") {
                @Override
                public void run() {
                    try {
                        log.debug("enter sleep");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        log.debug("wake up");
                        e.printStackTrace();
                    }
                }
            };
            t1.start();
            Thread.sleep(1000);
            log.debug("interrupt t1");
            //被喚醒
            t1.interrupt();
        }
    }

    執行結果

    Java線程中的start方法和run方法怎么使用

    上述代碼中,當$start$方法啟動后,$t1$線程進入睡眠狀態,打印提示信息,睡眠時間為$2s$,在$main$線程中睡眠$1s$后打斷$t1$線程的睡眠,提示打斷信息,并且調用$interrupt()$方法,此時線程被打斷,拋出異常。

    Java線程中的start方法和run方法怎么使用

    $TimeUnit$類中新增了以什么單位去睡眠,可讀性更好,但是本質上沒區別,只是進行了單位換算

    TimeUnit.SECONDS.sleep(1);//該語句作用是睡眠一秒

    yield

    調用$yield$會讓當前進程從$Running$進入到$Runnable$就緒狀態,然后調度執行其他線程具體的實現依賴于操作系統的任務調度器,(即當任務調度器中沒有其他任務時,即使讓出$cpu$,也會繼續執行該線程)$sleep$執行后是進入阻塞狀態,此時睡眠時間不結束,就不會分配$cpu$給該線程,但是$yield$是進入就緒狀態,即如果沒有其他線程需要執行,那么還會給該線程分配時間片,這是$sleep$和$yield$的最大區別線程優先級

    線程優先級

    會提示調度器優先調度該線程,但它僅僅是一個提示,調度器可以忽略他
    如果$cpu$比較忙,那么優先級高的會獲得更多的時間片,可$cpu$空閑時,優先級幾乎沒有

    sleep的應用-防止cpu占用100%

    在沒有利用$cpu$來計算時,不要讓$while(true)$空轉浪費$cpu$,這時可以可以使用$yield$或者$sleep$來讓$cpu$的使用權交給其他程序

    while (true) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
      }
    }

    可以使用$wait$或者條件變量達到類似的效果
    不同的是后兩者都需要加鎖,并且需要相應的喚醒操作,一般適用于要進行同步的場景
    $sleep$適用于無需鎖同步的場景

    join方法

    以下程序的打印結果:

    @Slf4j(topic = "c.Test6")
    public class Test6 {
        static int r = 0;
        public static void main(String[] args) {
            test();
        }
        private static void test() {
            log.debug("開始");
            Thread t = new Thread("t1") {
                @Override
                public void run() {
                    log.debug("開始");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.debug("結束");
                    r = 10;
                }
            };
            t.start();
            log.debug("r的值是{}", r);
            log.debug("結束");
        }
    }

    Java線程中的start方法和run方法怎么使用

    因為主線程和$t1$線程是并行的,$t1$線程需要$1s$后才能計算出$r$的值,而主線程一開始就要打印出$r$的值,因此打印的值為0

    解決方法:

    在$t.start();$后邊加上$t.join();$即可。$join$的作用是等待某線程運行結束。
    以調用方的角度來說,需要等待結果返回才能繼續執行就是同步,不需要等待返回結果就能繼續執行的就是異步。

    Java線程中的start方法和run方法怎么使用

    因此$join$方法實際上是讓其同步執行

    有實效的等待

    $join(毫秒)$方法里可以有一個參數是傳入等待的時間,如果線程執行時間大于等待時間,則等待時間到了之后,就會停止等待。如果線程執行時間小于等待時間,則線程執行完畢之后,等待也會跟著結束。不會把設置的等待時間過完。

    interrupt方法

    打斷$sleep, wait, join$的線程,即打斷阻塞狀態的線程
    打斷$sleep$的線程,會清空打斷狀態

    @Slf4j(topic = "c.Test7")
    public class Test7 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("sleep...");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            t.start();
            Thread.sleep(1000);
            log.debug("interrupt");
            t.interrupt();
            log.debug("打斷標記: {}", t.isInterrupted());
        }
    }

    Java線程中的start方法和run方法怎么使用

    打斷正常運行的線程,不會清空打斷狀態

    因此我們可以在線程中判斷打斷標記,來決定是否被打斷,以及執行被打斷之前的收尾工作。

    @Slf4j(topic = "c.Test8")
    public class Test8 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1"){
                @Override
                public void run() {
                    while (true) {
                        if (Thread.currentThread().isInterrupted()) {
                            log.debug("線程被打斷了");
                            break;
                        }
                    }
                }
            };
            t.start();
            Thread.sleep(1000);
            log.debug("interrupt");
            t.interrupt();
        }
    }

    守護線程

    默認情況下,$java$需要等待所有線程都運行結束,才會結束。有一種特殊的線程叫做守護線程,只要其他非守護線程運行結束了,即使守護線程的代碼沒有執行完畢,也會強制結束。

    @Slf4j(topic = "c.Test10")
    public class Test10 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1") {
                @Override
                public void run() {
                    while (true) {
    
                    }
                }
            };
            //設置線程為守護線程
            t.setDaemon(true);
            t.start();
            Thread.sleep(1000);
            log.debug("主線程結束");
        }
    }

    如果不把$t$設置為守護線程,則因為線程內部的死循環,導致程序不會結束運行。

    “Java線程中的start方法和run方法怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    山西省| 大连市| 清流县| 衡水市| 东宁县| 瑞金市| 商城县| 西平县| 明光市| 湟源县| 仁怀市| 桐庐县| 伊吾县| 肇东市| 屯门区| 孟津县| 岑巩县| 蒙山县| 普格县| 马龙县| 都兰县| 拉孜县| 墨玉县| 汉中市| 潞西市| 那曲县| 高碑店市| 大连市| 霍林郭勒市| 钦州市| 凭祥市| 苍梧县| 江都市| 巴楚县| 泸州市| 东台市| 长泰县| 河曲县| 长宁县| 扎赉特旗| 祁阳县|