work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

notify和notifyAll的区别

Posted on 2019-12-28 21:53  work hard work smart  阅读(1377)  评论(0编辑  收藏  举报

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

  说明三个线程都被唤醒了