#根本區別:sleep是Thread類別中的方法,不會馬上進入運作狀態,wait是Object類別中的方法,一旦物件呼叫了wait方法,就必須採用notify()和notifyAll()方法喚醒該進程
釋放同步鎖定:sleep會釋放cpu,但是sleep不會釋放同步鎖定的資源,wait會釋放同步鎖定資源
使用範圍:sleep可以在任何地方使用,但wait只能在synchronized的同步方法或是程式碼區塊中使用
異常處理: sleep需要捕獲異常,而wait不需要捕獲異常
讓目前執行程式碼的執行緒進行等待. (把執行緒放到等待佇列中)
釋放目前的鎖定
#滿足某一條件時被喚醒, 重新嘗試取得這個鎖定.
wait 要搭配synchronized 來使用,脫離synchronized 使用wait 會直接拋出例外.
wait方法
/** * wait的使用 */ public class WaitDemo1 { public static void main(String[] args) { Object lock = new Object(); Thread t1 = new Thread(() -> { System.out.println("线程1开始执行"); try { synchronized (lock) { System.out.println("线程1调用wait方法...."); // 无限期的等待状态 lock.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1执行完成"); }, "线程1"); t1.start(); } }
有參wait線程和無參子wait線程
/** * 有参wait线程和无参wait线程 */ public class WaitDemo2 { public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(()->{ System.out.println("线程1开始执行"); synchronized (lock1){ try { lock1.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1执行完成"); } },"无参wait线程"); t1.start(); Thread t2 = new Thread(()->{ System.out.println("线程2开始执行"); synchronized (lock2){ try { lock2.wait(60*60*1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2执行完成"); } },"有参wait线程"); t2.start(); } }
①其他執行緒呼叫該物件的notify 方法.
②wait 等待時間超時(wait 方法提供一個帶有timeout 參數的版本, 來指定等待時間).
③其他執行緒呼叫該等待執行緒的interrupted 方法, 導致wait 拋出InterruptedException 例外
notify 方法只是喚醒某一個等待的執行緒
方法notify()也要在同步方法或同步區塊中調用,該方法是用來通知那些可能等待該物件的物件鎖的其它線程
如果有多個執行緒等待,隨機挑選一個wait狀態的執行緒
在notify()方法後,目前執行緒不會馬上釋放該物件鎖,要等到執行notify()方法的執行緒將程式執行完,也就是退出同步程式碼區塊之後才會釋放物件鎖定
#notify方法的使用
/** * wait的使用, 如果有多个线程等待,随机挑选一个wait状态的线程 */ public class WaitNotifyDemo { public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(()->{ System.out.println("线程1开始执行"); try { synchronized (lock1) { System.out.println("线程1调用wait方法"); lock1.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1执行完成"); },"线程1"); Thread t2 = new Thread(()->{ System.out.println("线程2开始执行"); try { synchronized (lock1) { System.out.println("线程2调用wait方法"); lock1.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2执行完成"); },"线程2"); t1.start(); t2.start(); // 唤醒 lock1 对象上休眠的线程的(随机唤醒一个) Thread t3 = new Thread(()->{ try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程3开始执行"); synchronized (lock1){ //发出唤醒通知 System.out.println("执行了唤醒"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } },"线程3"); t3.start(); } }
notifyAll方法可以一次喚醒所有的等待執行緒
notifyAll方法的使用
/** * notifyAll-唤醒所有线程 */ public class WaitNotifyAll { public static void main(String[] args) { Object lock = new Object(); new Thread(() -> { System.out.println("线程1:开始执行"); synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1:执行完成"); } }, "无参wait线程").start(); new Thread(() -> { synchronized (lock) { System.out.println("线程2:开始执行 |" + LocalDateTime.now()); try { lock.wait(60 * 60 * 60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2:执行完成 | " + LocalDateTime.now()); } }, "有参wait线程").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock) { System.out.println("唤醒所有线程"); lock.notifyAll(); } }).start(); } }
notify和notifyAll方法的差異
當你呼叫notify時,只有一個等待執行緒會被喚醒而且它不能保證哪個執行緒會被喚醒,這取決於執行緒調度器。
呼叫notifyAll方法,那麼等待該鎖定的所有執行緒都會被喚醒,但是在執行剩餘的程式碼之前,所有被喚醒的執行緒都將爭奪鎖定,這就是為什麼在循環上呼叫wait,因為如果多個執行緒被喚醒,那麼執行緒是將獲得鎖定將首先執行,它可能會重置等待條件,這將迫使後續執行緒等待。
因此,notify和notifyAll之間的關鍵區別在於notify()只會喚醒一個線程,而notifyAll方法將喚醒所有執行緒。
以上是Java中sleep和wait方法有什麼差別的詳細內容。更多資訊請關注PHP中文網其他相關文章!