notify和notifyAll的區別


1、我們先驗證下wait可以用notify和notifyAll來喚醒

如下測試代碼:

public class WaitSleepDemo {

    public static void main(String[] args) {
        final  Object lock = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread A is waiting to get lock");
                synchronized (lock){

                    try {
                        System.out.println("thread A get lock");
                        Thread.sleep(20);
                        System.out.println("thread A do wait method");
                        //無限期的等待
                        lock.wait();
                        //Thread.sleep(1000);
                        System.out.println("thread A is done");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();


        //為了讓Thread A 先於Thread B執行
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread B is waiting to get lock");
                synchronized (lock){
                    try {
                        System.out.println("thread B get lock");
                        System.out.println("thread B is sleeping 10 ms");
                       Thread.sleep(10);
                       // lock.wait(10);
                        System.out.println("thread B is done");
                        //這句注釋掉,thread A is done就不會被打印
                        lock.notify(); // lock.notifyAll();
                       

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }).start();
    }
}

  

  執行結果:

thread A is waiting to get lock
thread A get lock
thread B is waiting to get lock
thread A do wait method
thread B get lock
thread B is sleeping 10 ms
thread B is done
thread A is done

  

 

2、notify和notifAll的區別

兩個概念

鎖池EntryList

等待池 WaitSet

 

鎖池:

假設線程A已經擁有了某個對象(不是類)的鎖,而其它線程B,C想要調用這個對象的某個某個synchronized方法(或者塊)之前必須獲得該對象鎖的擁有權,而恰巧該對象的鎖目前正被A所占有,此時B, C線程就會被阻塞,進入一個地方去等待鎖的釋放,這個地方便是該對象的鎖池。

等待池

   假設線程A調用了某個對象的wait方法,線程A就會釋放該對象的鎖,同時線程A就進入到了該對象的等待池中,進入等待池中的線程不會去競爭該對象的鎖。

 notify和notifAll的區別

notifyAll: 會讓所有處於等待池的線程全部進入鎖池去競爭獲取鎖的機會

notify: 只會隨機選取一個處於等待池中的線程進入鎖池去競爭獲取鎖的機會。

 

 

如下的測試代碼

public class NotificationDemo {
    private volatile boolean go = false;


    private synchronized  void shouldGo() throws InterruptedException {

        while (go != true){
            System.out.println(Thread.currentThread() + " is going to wait on this object");
            wait();
            System.out.println(Thread.currentThread() + " is woken up");

        }
        go = false; //reseting condition
    }


    private synchronized  void go() throws InterruptedException {

        while (go == false){
            System.out.println(Thread.currentThread() + " is going to notify all or one ");
            go = true;

            notify();
        }

    }



    public static void main(String[] args) throws InterruptedException {

        NotificationDemo test = new NotificationDemo();

          Runnable waitTak = new Runnable() {
            @Override
            public void run() {
                try {
                    test.shouldGo();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " finish execution");
            }
        };

         Runnable notifyTask = new Runnable() {
            @Override
            public void run() {
                try {
                    test.go();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " finish execution");
            }
        };

        Thread t1 = new Thread(waitTak, "WT1");
        Thread t2 = new Thread(waitTak, "WT2");
        Thread t3 = new Thread(waitTak, "WT3");
        t1.start();
        t2.start();
        t3.start();

        Thread t4 = new Thread(notifyTask, "NT1");
        Thread.sleep(200);
        t4.start();


    }
}

  打印結果:

Thread[WT1,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one 
Thread[WT1,5,main] is woken up
NT1 finish execution
WT1 finish execution

  多執行幾次,可以發現notify調用后,被喚醒的線程是隨機的。

 

將notify改成notifyAll

 

 打印結果如下:

Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one 
Thread[WT2,5,main] is woken up
Thread[WT3,5,main] is woken up
Thread[WT3,5,main] is going to wait on this object
NT1 finish execution
Thread[WT1,5,main] is woken up
Thread[WT1,5,main] is going to wait on this object
WT2 finish execution

  說明三個線程都被喚醒了


免責聲明!

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



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