java线程的wait和notify方法的说明


前言

我们线程的执行是抢占式的,线程的执行是我们不可预测的,但实际的开发中,我们希望合理的协调多个线程同时进行,但是要怎么办呢?于是我们就引入这个wait和notify的方法,接下来我们来介绍这俩个方法的应用场景和具体是怎么使用的.

一.wait方法

wait方法要做的事情:
使当前执行代码的线程进行等待. (把线程放到等待队列中)
释放当前的锁
满足一定条件时被唤醒, 重新尝试获取这个锁.
这样吧,我们来个例子来说明一下:

public class ThreadDemo20 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        System.out.println("wait 之前");
        synchronized (object) {
            object.wait();
        }
        System.out.println("wait 之后");
    }
}

当然这个程序运行起来之后,你会觉得很疑惑

在这里插入图片描述
实际上就是没有结束的,它相当于一直让线程进入了阻塞状态,当然我们线程必须有结束条件的.
结束条件:
其他线程调用该对象的 notify 方法.
wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.

当然我们先不对这个程序进行优化,先不使用notify方法,等我们介绍完notify方法是什么以后,然后对上述程序加一个notify方法.


二.notify方法

这里大概的列出它的方法概述:
方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的
其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)
在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行
完,也就是退出同步代码块之后才会释放对象锁。

可能上面说了一大堆,你也没怎么明白,是怎么回事,我们来一个实际的生活例子,你就应该会明白了.

在这里插入图片描述
当然这个例子可能还是不好,但在后面我们会继续用一些实际性的例子,去让你慢慢明白的,不用着急.
接下来,要回到我们刚开始的那一个程序,我们要让wait结束,并唤醒,看完我接下来写的代码,或许你会有一定的思路.

public class ThreadDemo21 {
    public static void main(String[] args) throws InterruptedException {
        Object locker =new Object();
        Thread t1=new Thread(() ->{
            try {
            System.out.println("wait 开始");
            synchronized (locker){
                    locker.wait();
            }
                System.out.println("wait 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(() -> {
            synchronized (locker) {
                System.out.println("notify 开始");
                locker.notify();
                System.out.println("notify 结束");
            }
        });
        t2.start();
    }
}

在这里插入图片描述
当然执行结果如下图所示:
在这里插入图片描述

那如果我们的t1线程比t2线程后执行呢?那又会是什么结果呢?
大家看我用文字描述一番

如果线程t2先于线程t1运行,并调用了notify方法,但此时线程t1还没有调用wait方法,那么notify方法会没有任何效果,线程t1仍然会进入等待状态。输出结果如下:
wait 开始
notify 开始
notify 结束

代码更改就不展示了.因为只是线程的执行顺序不同,但执行效果如下:
在这里插入图片描述
从这里我们就可以发现,notify实际上是要和wait搭配使用的.如果没有陷入阻塞等待的线程,notify也不会报出异常,wait方法将一直等待下去,所以在这方面,我们还是要谨慎的.介绍完notify以后,我们还有一个notifyAll方法没有解释.

三.notifyAll方法

notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程.
我们接上文的例子,重新对原来的例子进行一些改进,看效果如下:

public class ThreadDemo22 {
    public static void main(String[] args) throws InterruptedException {
        Object locker =new Object();
        Thread t1=new Thread(() ->{
            try {
                System.out.println("wait 开始");
                synchronized (locker){
                    locker.wait();
                }
                System.out.println("wait 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        Thread t3=new Thread(() ->{
            try {
                System.out.println("wait 开始");
                synchronized (locker){
                    locker.wait();
                }
                System.out.println("wait 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        Thread t4=new Thread(() ->{
            try {
                System.out.println("wait 开始");
                synchronized (locker){
                    locker.wait();
                }
                System.out.println("wait 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });



        Thread t2 = new Thread(() -> {
            synchronized (locker) {
                System.out.println("notifyAll 开始");
                locker.notifyAll();
                System.out.println("notifyAll 结束");
            }
        });
        t1.start();
        t3.start();
        t4.start();
        Thread.sleep(1000);
        t2.start();


    }
}

执行结果:
在这里插入图片描述
此时可以看到, 调用 notifyAll 能同时唤醒 3 个wait 中的线程
当然特别注意,我们这里: 虽然是同时唤醒 3 个线程, 但是这 3 个线程需要竞争锁. 所以并不是同时执行, 而仍然是有先有后的执行.
比如那下面的图示举例子:
notify只唤醒等待队列中的一个线程. 其他线程还是乖乖等着
在这里插入图片描述
notifyAll 一下全都唤醒, 需要这些线程重新竞争锁
在这里插入图片描述

到这里大家先别急,我们先把这个篇文章结束,接下来的知识,我们在下一篇文章继续循序渐进

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忘忧记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值