美文网首页
09给女朋友讲讲并发编程-wait()和notify()

09给女朋友讲讲并发编程-wait()和notify()

作者: XueFengDong | 来源:发表于2021-01-15 21:02 被阅读0次

一、API介绍

  • obj.wait() 让进入object监视器的线程到waitSet中等待(RUNNBALE -> TIMED_WAITING)
  • obj.notify() 随机唤醒一个waitSet中阻塞的线程
  • obj.notifyAll() 唤醒在waitSet中所有阻塞的线程
    上面三个方法都是线程间协作的手段,都属于Object对象的方法。必须获得此对象的锁,才可以调用这几个方法。
    static Object obj = new Object();
    
    public static void main(String[] args){

        Thread t2 = new Thread(() -> {

            synchronized (obj){
                log.info("{}","t1进入等待...");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("t1被唤醒");
            }

        }, "t1");

        Thread t1 = new Thread(() -> {

            synchronized (obj){
                log.info("{}","t2进入等待...");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("t2被唤醒");
            }

        }, "t2");

        t1.start();
        t2.start();

        try {
            //主线程休眠2秒
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (obj){
            log.info("{}","主线程随机唤醒一个线程");
            obj.notify();
        }
        
    }

输出结果:

21:35:24.174  INFO [t1] com.dxf.线程的方法.Test9 - t1进入等待...
21:35:24.175  INFO [t2] com.dxf.线程的方法.Test9 - t2进入等待...
21:35:26.173  INFO [main] com.dxf.线程的方法.Test9 - 主线程随机唤醒一个线程
21:35:26.173  INFO [t1] com.dxf.线程的方法.Test9 - t1被唤醒

如果换成notifyAll():

21:36:46.677  INFO [t2] com.dxf.线程的方法.Test9 - t2进入等待...
21:36:46.678  INFO [t1] com.dxf.线程的方法.Test9 - t1进入等待...
21:36:48.677  INFO [main] com.dxf.线程的方法.Test9 - 主线程唤醒全部waitSet中的线程
21:36:48.677  INFO [t1] com.dxf.线程的方法.Test9 - t1被唤醒
21:36:48.677  INFO [t2] com.dxf.线程的方法.Test9 - t2被唤醒

二、wait()和sleep()的区别

  • sleep()是Thread类中的方法,wait()是object类中的方法.
  • sleep()可以在任意位置执行,wait()只能在synchronized中获取到对象锁执行.
  • sleep()在synchronized中执行不会释放对象锁,wait()则会进入waitSet队列中等待同时释放锁.

三、wait()和notify()的正确使用姿势

大家看下面一段代码:

 static final Object lock = new Object();

    static boolean flag = false;

    static boolean hasDinner = false;

    /**
     * 现在有两个线程
     * t1线程:需要有烟才能干活
     * t2线程:等待外卖,外卖到了开始吃饭
     * @param args
     */
    public static void main(String[] args) {

        new Thread(() ->{
            synchronized (lock){
                while (!flag){
                    //如果flag为false,则进入等待(会释放锁),当为ture时才会往下走
                    try {
                        log.info("{}","没有烟...不能干活...");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                log.info("开始干活");

            }

        },"t1").start();

        new Thread(() ->{
            synchronized (lock){
                while (!hasDinner){
                    //如果flag为false,则进入等待(会释放锁),当为ture时才会往下走
                    try {
                        log.info("{}","等待外卖...");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                log.info("外卖到了...开始吃饭...");

            }

        },"t2").start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (lock){
            hasDinner = true;
            lock.notify();
        }

    }

当主线程将送外卖的变量改为ture,表示外卖到了,t2线程应该被唤醒。可如果使用了notify()方法,只能随机唤醒一个在waitSet中的线程,输出结果:

20:56:33.551  INFO [t1] com.dxf.线程的方法.Test10 - 没有烟...不能干活...
20:56:33.552  INFO [t2] com.dxf.线程的方法.Test10 - 等待外卖...
20:56:35.552  INFO [t1] com.dxf.线程的方法.Test10 - 没有烟...不能干活...

我们发现t1线程被唤醒了,并且不能继续往下执行,跟我们想的有偏差,如何解决?
使用notifyAll().唤醒全部等待的线程,满足条件的会继续执行,不满足的则继续进入等待.

21:01:35.830  INFO [t1] com.dxf.线程的方法.Test10 - 没有烟...不能干活...
21:01:35.832  INFO [t2] com.dxf.线程的方法.Test10 - 等待外卖...
21:01:37.830  INFO [t2] com.dxf.线程的方法.Test10 - 外卖到了...开始吃饭...
21:01:37.830  INFO [t1] com.dxf.线程的方法.Test10 - 没有烟...不能干活...

相关文章

网友评论

      本文标题:09给女朋友讲讲并发编程-wait()和notify()

      本文链接:https://www.haomeiwen.com/subject/fbdbaktx.html