面試突擊25:sleep和wait有什么區別


sleep 方法和 wait 方法都是用來將線程進入休眠狀態的,並且 sleep 和 wait 方法都可以響應 interrupt 中斷,也就是線程在休眠的過程中,如果收到中斷信號,都可以進行響應,並拋出 InterruptedException 異常。那 sleep 和 wait 的區別都有哪些呢?接下來,我們一起來看。

區別一:語法使用不同

wait 方法必須配合 synchronized 一起使用,不然在運行時就會拋出 IllegalMonitorStateException 的異常,如下代碼所示:
image.png
初看代碼好像沒啥問題,編譯器也沒報錯,然而當我們運行以上程序時就會發生如下錯誤:
image.png
而 sleep 可以單獨使用,無需配合 synchronized 一起使用。

區別二:所屬類不同

wait 方法屬於 Object 類的方法,而 sleep 屬於 Thread 類的方法,如下圖所示:
image.png

區別三:喚醒方式不同

sleep 方法必須要傳遞一個超時時間的參數,且過了超時時間之后,線程會自動喚醒。而 wait 方法可以不傳遞任何參數,不傳遞任何參數時表示永久休眠,直到另一個線程調用了 notify 或 notifyAll 之后,休眠的線程才能被喚醒。也就是說 sleep 方法具有主動喚醒功能,而不傳遞任何參數的 wait 方法只能被動的被喚醒

區別四:釋放鎖資源不同

wait 方法會主動的釋放鎖,而 sleep 方法則不會。接下來我們使用代碼的方式來演示一下二者的區別。

sleep 不釋放鎖

接下來使用 sleep 是線程休眠 2s,然后在另一個線程中嘗試獲取公共鎖,如果能夠獲取到鎖,則說明 sleep 在休眠時會釋放鎖,反之則說明不會釋放鎖,實現代碼如下:

public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();
    new Thread(() -> {
        synchronized (lock) {
            System.out.println("新線程獲取到鎖:" + LocalDateTime.now());
            try {
                // 休眠 2s
                Thread.sleep(2000);
                System.out.println("新線程獲釋放鎖:" + LocalDateTime.now());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
    // 等新線程先獲得鎖
    Thread.sleep(200);
    System.out.println("主線程嘗試獲取鎖:" + LocalDateTime.now());
    // 在新線程休眠之后,嘗試獲取鎖
    synchronized (lock) {
        System.out.println("主線程獲取到鎖:" + LocalDateTime.now());
    }
}

以上代碼的執行結果如下圖所示:
image.png
從上述結果可以看出,在調用了 sleep 之后,在主線程里嘗試獲取鎖卻沒有成功,只有 sleep 執行完之后釋放了鎖,主線程才正常的得到了鎖,這說明 sleep 在休眠時並不會釋放鎖。

wait 釋放鎖

接下來使用同樣的方式,將 sleep 替換成 wait,在線程休眠之后,在另一個線程中嘗試獲取鎖,實現代碼如下:

public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();
    new Thread(() -> {
        synchronized (lock) {
            System.out.println("新線程獲取到鎖:" + LocalDateTime.now());
            try {
                // 休眠 2s
                lock.wait(2000);
                System.out.println("新線程獲釋放鎖:" + LocalDateTime.now());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
    // 等新線程先獲得鎖
    Thread.sleep(200);
    System.out.println("主線程嘗試獲取鎖:" + LocalDateTime.now());
    // 在新線程休眠之后,嘗試獲取鎖
    synchronized (lock) {
        System.out.println("主線程獲取到鎖:" + LocalDateTime.now());
    }
}

以上代碼的執行結果如下圖所示:
image.png
從上述結果可以看出,當調用了 wait 之后,主線程立馬嘗試獲取鎖成功了,這就說明 wait 休眠時是釋放鎖的

區別五:線程進入狀態不同

調用 sleep 方法線程會進入 TIMED_WAITING 有時限等待狀態,而調用無參數的 wait 方法,線程會進入 WAITING 無時限等待狀態。
代碼演示:

public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();
    Thread t1 = new Thread(() -> {
        synchronized (lock) {
            try {
                // 休眠 2s
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.start();

    Thread t2 = new Thread(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t2.start();

    Thread.sleep(200);
    System.out.println("wait() 之后進入狀態:" + t1.getState());
    System.out.println("sleep(2000) 之后進入狀態:" + t2.getState());

}

以上代碼的執行結果如下:
image.png

總結

sleep 和 wait 都可以讓線程進入休眠狀態,並且它們都可以響應 interrupt 中斷,但二者的區別主要體現在:語法使用不同、所屬類不同、喚醒方式不同、釋放鎖不同和線程進入的狀態不同。

是非審之於己,毀譽聽之於人,得失安之於數。

公眾號:Java面試真題解析

面試合集:https://gitee.com/mydb/interview


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM