首頁 > Java > java教程 > Java中sleep和wait方法有什麼差別

Java中sleep和wait方法有什麼差別

WBOY
發布: 2023-05-06 09:52:06
轉載
1238 人瀏覽過

    一、sleep與wait方法的區別

    • #根本區別:sleep是Thread類別中的方法,不會馬上進入運作狀態,wait是Object類別中的方法,一旦物件呼叫了wait方法,就必須採用notify()和notifyAll()方法喚醒該進程

    • 釋放同步鎖定:sleep會釋放cpu,但是sleep不會釋放同步鎖定的資源,wait會釋放同步鎖定資源

    • 使用範圍:sleep可以在任何地方使用,但wait只能在synchronized的同步方法或是程式碼區塊中使用

    • 異常處理: sleep需要捕獲異常,而wait不需要捕獲異常

    二、wait方法

    • 讓目前執行程式碼的執行緒進行等待. (把執行緒放到等待佇列中)

    • 釋放目前的鎖定

    • #滿足某一條件時被喚醒, 重新嘗試取得這個鎖定.

    • wait 要搭配synchronized 來使用,脫離synchronized 使用wait 會直接拋出例外.

    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();
        }
    }
    登入後複製

    wait結束等待的條件

    ①其他執行緒呼叫該物件的notify 方法.

    ②wait 等待時間超時(wait 方法提供一個帶有timeout 參數的版本, 來指定等待時間).

    ③其他執行緒呼叫該等待執行緒的interrupted 方法, 導致wait 拋出InterruptedException 例外

    三、notify和notifyAll方法

    notify 方法只是喚醒某一個等待的執行緒

    1. 方法notify()也要在同步方法或同步區塊中調用,該方法是用來通知那些可能等待該物件的物件鎖的其它線程

    2. 如果有多個執行緒等待,隨機挑選一個wait狀態的執行緒

    3. 在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方法的差異

    1. 當你呼叫notify時,只有一個等待執行緒會被喚醒而且它不能保證哪個執行緒會被喚醒,這取決於執行緒調度器。

    2. 呼叫notifyAll方法,那麼等待該鎖定的所有執行緒都會被喚醒,但是在執行剩餘的程式碼之前,所有被喚醒的執行緒都將爭奪鎖定,這就是為什麼在循環上呼叫wait,因為如果多個執行緒被喚醒,那麼執行緒是將獲得鎖定將首先執行,它可能會重置等待條件,這將迫使後續執行緒等待。

    3. 因此,notify和notifyAll之間的關鍵區別在於notify()只會喚醒一個線程,而notifyAll方法將喚醒所有執行緒。

    #

    以上是Java中sleep和wait方法有什麼差別的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    相關標籤:
    來源:yisu.com
    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    熱門教學
    更多>
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板