<bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>

    寫在開頭

    在線程的生命周期中,不同狀態之間切換時,可以通過調用sleep()、wait()、join()、yield()等方法進行線程狀態控制,針對這一部分知識點,面試官們也會做做文章,比如問你這些方法的作用以及之間的區別。

    那么今天我們就一起來總結一下這幾個方法的作用及區別,先畫一個思維導圖梳理一下,便于理解與記憶,爭取在被問到這個點時徹底征服面試官?。?code>圖片可保存??垂?/code>)
    image

    sleep()

    sleep()是Thread類中的一個靜態本地方法,通過設置方法中的時間參數,使調用它的線程休眠指定時間,線程從RUNNING狀態轉為BLOCKED狀態,這個過程中會釋放CPU資源,給其他線程運行機會時不考慮線程的優先級,但如果有同步鎖則sleep不會釋放鎖即其他線程無法獲得同步鎖,需要注意的是sleep()使用時要處理異常。休眠時間未到時,可通過調用interrupt()方法來喚醒休眠線程。

    【代碼示例1】

    try {//sleep會發生異常要顯示處理
        Thread.sleep(20);//暫停20毫秒
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    

    為什么sleep()放在Thread類中

    答:因為sleep是線程級別的休眠,不涉及到對象類,只是讓當前線程暫停,進入休眠狀態,并不釋放同步鎖資源,也不需要去獲得對象鎖。

    wait()

    wait() 是Object類的成員本地方法,會讓持有對象鎖的線程釋放鎖,進入線程等待池中等待被再次喚醒(notify隨機喚醒,notifyAll全部喚醒,線程結束自動喚醒)即放入鎖池中競爭同步鎖,同時釋放CPU資源,它的調用必須在同步方法或同步代碼塊中執行,也需要捕獲 InterruptedException 異常。

    【代碼示例2】

    //同步代碼塊
     synchronized (obj) {
         System.out.println("obj to wait on RunnableImpl1");
         try {
             obj.wait();
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println("obj continue to run on RunnableImpl1");
     }
    

    為什么wait()是Object的方法

    答:每個對象都擁有對象鎖,wait的作用是釋放當前線程所占有的對象鎖,自然是要操作對應的Object而不是Thread,因此wait要放入到Object中。

    join()

    join()同樣是Thread中的一個方法,調用join的線程擁有優先使用CPU時間片的權利,其他線程需要等待join()調用線程執行結束后才能繼續執行,探索其底層會發現,它的底層是通過wait()進行實現,因此它也需要處理異常。

    【代碼示例3】

    //創建TestRunnable類
    TestRunnable mr = new TestRunnable();
    //創建Thread類的有參構造,并設置線程名
    Thread t1 = new Thread(mr, "t1");
    Thread t2 = new Thread(mr, "t2");
    Thread t3 = new Thread(mr, "t3");
    //啟動線程
    t1.start();
    try {
        t1.join(); //等待t1執行完才會輪到t2,t3搶
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    t2.start();
    t3.start();
    

    我們跟進join()方法內部會發現,其底層主要通過wait()實現,其中參數代表等待當前線程最多執行 millis 毫秒,如果 millis 為 0,則會一直執行,直至完成,其他線程才會繼續向下;

    【源碼示例1】

        public final synchronized void join(long millis)
        throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
                while (isAlive()) {
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }
    

    yield()

    yield()是Thread的一個靜態方法,它的調用不需要傳入時間參數,并且yield() 方法只會給相同優先級或更高優先級的線程運行的機會,并且調用yield的線程狀態會轉為就緒狀態,調用yield方法只是一個建議,告訴線程調度器我的工作已經做的差不多了,可以讓別的線程使用CPU了,沒有任何機制保證采納。所以可能它剛讓出CPU時間片,又被線程調度器分配了一個時間片繼續執行了。使用時不需要處理異常。

    【代碼示例4】

    public class Test {
    
        public static void main(String[] args) {
            Thread thread1 = new Thread(Test::printNumbers, "小明");
            Thread thread2 = new Thread(Test::printNumbers, "小華");
            thread1.start();
            thread2.start();
        }
        private static void printNumbers() {
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": " + i);
    
                // 當 i 是偶數時,當前線程暫停執行
                if (i % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + " 讓出控制權...");
                    Thread.yield();
                }
            }
        }
    }
    

    輸出:

    小明: 1
    小華: 1
    小華: 2
    小明: 2
    小明 讓出控制權...
    小華 讓出控制權...
    小明: 3
    小明: 4
    小明 讓出控制權...
    小明: 5
    小華: 3
    小華: 4
    小華 讓出控制權...
    小華: 5
    

    總結

    上文中,我們結合代碼示例,對這個四個方法進行了詳細介紹,下面我們以sleep()為參照,進行對比總結:

    (1)sleep()與wait()的區別?

    1. sleep() 是 Thread 類的靜態本地方法;wait() 是Object類的成員本地方法;
    2. JDK1.8 sleep() wait() 均需要捕獲 InterruptedException 異常;
    3. sleep() 方法可以在任何地方使用;wait() 方法則只能在同步方法或同步代碼塊中使用;
    4. sleep() 會休眠當前線程指定時間,釋放 CPU 資源,不釋放對象鎖,休眠時間到自動蘇醒繼續執行;wait() 方法放棄持有的對象鎖,進入等待隊列,當該對象被調用 notify() / notifyAll() 方法后才有機會競爭獲取對象鎖,進入運行狀態。

    (2)sleep()與yield()的區別?

    1. sleep() 方法給其他線程運行機會時不考慮線程的優先級;yield() 方法只會給相同優先級或更高優先級的線程運行的機會;
    2. sleep() 方法聲明拋出 InterruptedException;yield() 方法沒有聲明拋出異常;
    3. 線程執行 sleep() 方法后進入超時等待狀態;線程執行 yield() 方法轉入就緒狀態,可能馬上又得得到執行;
    4. sleep() 方法需要指定時間參數;yield() 方法出讓 CPU 的執行權時間由 JVM 控制。

    (3)sleep()與join()的區別?

    1. JDK1.8 sleep() join() 均需要捕獲 InterruptedException 異常;
    2. sleep()是Thread的靜態本地方法,join()是Thread的普通方法;
    3. sleep()不會釋放鎖資源,join()底層是wait方法,會釋放鎖。

    結尾彩蛋

    如果本篇博客對您有一定的幫助,大家記得留言+點贊+收藏呀。原創不易,轉載請聯系Build哥!

    image

    如果您想與Build哥的關系更近一步,還可以關注“JavaBuild888”,在這里除了看到《Java成長計劃》系列博文,還有提升工作效率的小筆記、讀書心得、大廠面經、人生感悟等等,歡迎您的加入!

    image

    posted on 2024-03-14 22:24  JavaBuild  閱讀(875)  評論(0編輯  收藏  舉報
    免费视频精品一区二区_日韩一区二区三区精品_aaa在线观看免费完整版_世界一级真人片
    <bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>