一、sleep是線程方法,wait是Object方法
這個如何驗證呢?我們還需要到jdk源碼中看看。首先進入到Thread的源碼中看一下,然後俺ctrl+O就可以查看方法列表。在最上面可以搜尋,我們輸入“s”,就可以查看所有以s開頭的方法了。
我們會發現,slee方法真實的在Thread線程類中。下面我們以同樣的方法查看wait。
這是第一個區別很容易驗證,下面我們來看第二個。
二、sleep不釋放lock,wait會釋放
這個如何驗證呢?這就需要代碼了。先看我們的sleep方法
public class Test { private final static Object lock = new Object(); public static void main(String[] args) { Stream.of("線程1","線程2").forEach(n->new Thread(n) { public void run(){ Test.testSleep(); } }.start()); } //sleep方法休眠之後, private static void testSleep() { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() +"正在執行"); Thread.sleep(10_000); System.out.println(Thread.currentThread().getName() +"休眠結束"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
我們看一下運行結果:
在上面的結果中,線程2先獲取了cpu資源,然後開始執行休眠,在休眠過程中線程1是沒法執行的,必須要等待線程2結束之後才可以。這也就是說sleep方法不會釋放鎖,讓其他線程進來。
然後我們測試一下wait方法。
public class Test { private final static Object lock = new Object(); public static void main(String[] args) { Stream.of("線程1", "線程2").forEach(n -> new Thread(n) { public void run() { Test.testWait(); } }.start()); } private static void testWait() { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + "正在執行"); lock.wait(10_000); System.out.println(Thread.currentThread().getName() + "wait結束"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
在上面的例子中,我們使用wait方法等待10秒鐘,然後結束。我們看一下結果:
這個過程就驗證了第二條區別,我們接下來看第三個。
三、sleep不依賴同步方法,wait需要
我們還是依次來驗證。首先我們測試sleep方法。
public class Test2 { private final static Object lock = new Object(); public static void main(String[] args) { Stream.of("線程1", "線程2").forEach(n -> new Thread(n) { public void run() { Test2.testSleep(); } }.start()); } private static void testSleep() { try { Thread.sleep(10_000); System.out.println("休眠結束"); } catch (InterruptedException e) { e.printStackTrace(); } } }
這個方法會依次運行,不會出現任何異常。然後我們主要是看wait方法。
public class Test2 { private final static Object lock = new Object(); public static void main(String[] args) { Stream.of("線程1", "線程2").forEach(n -> new Thread(n) { public void run() { Test2.testSleep(); } }.start()); } private static void testWait() { try { lock.wait(10_000); System.out.println("wait結束"); } catch (InterruptedException e) { e.printStackTrace(); } } }
我們運行一下,看一下結果:
OK,下面我們驗證一下第四條區別:
四、sleep不需要被喚醒,wait需要
sleep方法很簡單,我們主要關注wait方法。看代碼:
首先我們定義兩個方法,一個等待方法,一個喚醒方法。
public class Test2 { private final static Object lock = new Object(); private static void testWait() { synchronized (lock) { try { System.out.println("我一直在等待"); lock.wait(); System.out.println("wait被喚醒了"); } catch (InterruptedException e) { e.printStackTrace(); } } } private static void notifyWait() { synchronized (lock) { try { Thread.sleep(5_000); lock.notify(); System.out.println("休眠5秒鐘喚醒wait"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
然後再去測試一下:
public class Test2 { private final static Object lock = new Object(); public static void main(String[] args) { new Thread() {//這個線程一直在等待 public void run() { Test2.testWait(); } }.start(); new Thread() {//這個線程準備去喚醒 public void run() { Test2.notifyWait(); } }.start(); } }
如果沒有喚醒方法,那第一個線程就會處於一直等待的狀態,第二個線程喚醒了之後就不再等待了。
以上就是四個區別的完整驗證,如有問題還請指正。