Java基礎wait和sleep的區別

 閱讀大約需要2分鐘

Java基礎wait和sleep的區別

1、sleep是Thread中的方法,是靜態方法,wait是Object中的方法,是實例方法。

2、sleep主要作用使線程暫停執行一段時間,時間一到自動恢復,不涉及線程通訊,不會去釋放鎖,但是wait會釋放這個鎖,並把這個wait的線程加入到這個鎖的等待隊列中去

3、sleep方法不依賴於同步器synchronized,但是wait需要依賴synchronized關鍵字。

4、sleep不需要被喚醒(休眠之後退出阻塞),但是wait需要(不指定時間需要被別人中斷)。

5、sleep一般用於當前線程休眠,或者輪循暫停操作,wait多用於多線程之間的通信。

sleep和wait使用時都需要捕獲InterruptedException異常,在調用後都會暫停當前線程,並讓出CPU的執行時間,但不同的是sleep不會釋放當前持有的對象的鎖資源, 到時間後會繼續執行,而wait會放棄所有鎖並需要notify/notifyAll後重新獲取到對象鎖資源後才能繼續執行。

Thread.sleep(1000) 意思是在未來的1000毫秒內本線程不參與CPU競爭,1000毫秒過去之後,這時候也許另外一個線程正在使用CPU,那麼這時候操作系統是不會重新分配CPU的,直到那個線程掛起或結束,即使這個時候恰巧輪到操作系統進行CPU分配,那麼當前線程也不一定就是總優先級最高的那個,CPU還是可能被其他線程搶占去。另外值得一提的是Thread.Sleep(0)的作用,就是觸發操作系統立刻重新進行一次CPU競爭,競爭的結果也許是當前線程仍然獲得CPU控制權,也許會換成別的線程獲得CPU控制權。

wait(1000)表示將鎖釋放1000毫秒,到時間後如果鎖沒有被其他線程佔用,則再次得到鎖,然後wait方法結束,執行後面的代碼,如果鎖被其他線程佔用,則等待其他線程釋放鎖。注意,設置了超時時間的wait方法一旦過了超時時間,並不需要其他線程執行notify也能自動解除阻塞,但是如果沒設置超時時間的wait方法必須等待其他線程執行notify。

sleep不會釋放鎖的例子如下:

public class SleepLockTest {
    private final static Object lock = new Object();

    public static void main(String[] args) {
        Stream.of("thread1", "thread2").forEach(x -> new Thread(x) {
            @Override
            public void run() {
                SleepLockTest.testSleep();
            }
        }.start());
    }

    private static void testSleep() {
        synchronized (lock) {

            try {
                System.out.println(Thread.currentThread().getName() + " is running");
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName() + " finish");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

運行結果如下:

thread1 is running:1650637494109
thread1 finish
thread2 is running:1650637499111
thread2 finish

wait會釋放鎖的例子如下:

public class WaitLockTest {
    private final static Object LOCK = new Object();

    public static void main(String[] args) {
        Stream.of("thread1", "thread2").forEach(x -> new Thread(x) {
            @Override
            public void run() {
                WaitLockTest.testWait();
            }
        }.start());
    }

    private static void testWait() {
        synchronized (LOCK) {

            try {
                System.out.println(Thread.currentThread().getName() + " is running:"+System.currentTimeMillis());
                LOCK.wait();
                System.out.println(Thread.currentThread().getName() + " finish");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

運行結果如下:

thread1 is running:1650637686502
thread2 is running:1650637686502

使用wait必須要定義一個synchronized,而sleep不需要

如下代碼wait沒有在synchronized代碼塊內

public class WaitNoSync {
    private final static Object LOCK = new Object();

    public static void main(String[] args) {
        new Thread(() -> WaitNoSync.testWait()).start();
        
    }

    private static void testWait() {
        try {
            System.out.println(Thread.currentThread().getName() + " is running:" + System.currentTimeMillis());
            LOCK.wait();
            System.out.println(Thread.currentThread().getName() + " finish");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

運行結果如下:

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at com.company.thread.WaitNoSync.testWait(WaitNoSync.java:18)
	at com.company.thread.WaitNoSync.lambda$main$0(WaitNoSync.java:11)
	at java.lang.Thread.run(Thread.java:748)