欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 【JavaEE初阶】深入理解wait和notify以及线程饿死的解决

【JavaEE初阶】深入理解wait和notify以及线程饿死的解决

2024/10/23 8:55:44 来源:https://blog.csdn.net/GGBond778/article/details/142611267  浏览:    关键词:【JavaEE初阶】深入理解wait和notify以及线程饿死的解决

前言:

🌈上期博客:【JavaEE初阶】深入解析死锁的产生和避免以及内存不可见问题-CSDN博客

🔥感兴趣的小伙伴看一看小编主页:【JavaEE初阶】深入解析死锁的产生和避免以及内存不可见问题-CSDN博客

⭐️小编会在后端开发的学习中不断更新~~~  

🥳非常感谢你的支持

 

目录

📚️1.引言

 📚️2.wait和notify

2.1wait作用

 2.2使用场景和线程饿死

 2.3wait如何使用

1.wait的锁对象

2.wait必须在synchronized内

3.调用wait的锁对象

4.notify的使用

📚️3.理解执行顺序

📚️4.注意事项

4.1wait不同的方法

4.2notify唤醒wait

4.3wait和sleep的区别

📚️5.总结


 

📚️1.引言

 OK啊!!!小伙伴们,在上期继小编讲解过死锁的问题后,本期将开始理解wait和notify的线程问题,那么废话不多说,直接步入正题,go go go~~~;

且听小编讲解,包你学会!!! 

 📚️2.wait和notify

2.1wait作用

这里的作用和上期讲解过的join有异曲同工之妙,都是在多线程随机调度中,通过引入wait和notify来实现干预不同线程的执行顺序,让后执行的线程不被调度,让先执行的线程把对应的代码执行完

 2.2使用场景和线程饿死

例如一个现实场景:取钱问题~~~

这里的ATM可能是没有钱的,那么此时当一个人去取完钱后,解锁后,其他滑稽老铁进入锁的竞争,但是此时刚刚取钱的滑稽老铁也会参与到锁的竞争,就导致此时壹号滑稽老铁由于竞争,和ATM没有钱,而一直反复获取锁,而导致其他的滑稽不能拿到锁,这就是“线程饿死” 

注意:由于已经拿到锁的滑稽老铁会处于RUNNABLE状态,但是其他线程处于阻塞状态,那么此时就是“近水楼台先得月” ,其他线程需要进行唤醒,才能参与到锁的竞争,那么就会导致壹号滑稽老铁更容易获取到锁~~~

此时就要运用到wait和notify了,让线程满足条件进行加锁执行,若不满足条件,那么就进入wait,直到满足条件后被notify唤醒~~~

下面是一个伪代码

 public static void main(String[] args) {while (true){synchronized (){if (ATM中有钱){进行取钱的操作 break;}else {进入等待;wait(){直到有钱然后被唤醒}}}}}

所以这就是我们所需要看到的情况;

注意:wait在这里做了三件事情

1.释放锁,让其他线程获取锁

2.让线程进入阻塞状态

3.被notify唤醒后,重新参与锁的竞争

 2.3wait如何使用

1.wait的锁对象

这里和加锁是一样的都是需要锁对象,当然这里的锁对象是可以为任何对象的,小编就不再过多解释

2.wait必须在synchronized内

此时如果我们将wait写到synchronized之外,代码如下:

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

输出打印日志:

wait 之前
Exception in thread "main" java.lang.IllegalMonitorStateExceptionat java.lang.Object.wait(Native Method)at java.lang.Object.wait(Object.java:502)at thread.testDemo17.main(testDemo17.java:7)

可以看到此时程序报错了;

注意:wait使用的前提是存在锁,所以在使用wait之前线程必须先获取锁。

3.调用wait的锁对象

在调用wait的锁对象必须和加锁的synchronized是同一个锁对象,所以wait解锁是synchronized的锁,重新唤醒后加锁也是synchronized的锁,代码如下:

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

此时输出就只有wait之前,因为此时线程进入阻塞了,咱们打开jconsole可以看出到此时的线程状况,如图所示:

此时代码进入WAITING状态~~~

4.notify的使用

注意此时,notify使用与其他的线程,并且调用notify的锁对象,也必须和调用wait的锁对象必须是一样的,唤醒的即对应锁对象调用的wait方法的线程;

📚️3.理解执行顺序

这里需要注意,在使用wait和notify后的代码是如何进行执行的,代码实例如下:

public static void main(String[] args) {Object lock=new Object();//创建线程1Thread t1=new Thread(()->{synchronized (lock){System.out.println("wait之前");try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("wait之后");}});Thread t2=new Thread(()->{try {Thread.sleep(1000);//保证线程1能够成功加上锁} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (lock){System.out.println("notify之前");lock.notify();System.out.println("notify之后");}});t1.start();t2.start();}

注意:小编这里为了保证线程1成功加上锁,那么在执行线程2时,就会进入休眠;还有wait和sleep一样,都有可能会被interrupt提前唤醒,所以这里在写wait时,需要进行异常抛出;

输出结果:

那么此时的执行顺序就是如下的:

1.首先线程1开始执行,加锁后执行打印“wait之前”,然后进入等待状态,释放锁并进入阻塞状态;

2.线程2开始执行,获取到锁后打印“notify之前”,然后唤醒线程一;

3.由于线程1处于WAITING状态,被唤醒后,由于锁的竞争会处于一个小小的阻塞,在获取锁这个阶段需要时间开销,所以先打印“notify之后”

4.最后线程1获取到锁后,最后执行最后的打印“wait之后”

📚️4.注意事项

4.1wait不同的方法

在进行wait方法的调用时,可以看到有三个其他的版本,如下图:

第一种:即死等,若没有进程进行唤醒操作,此时就会导致这个线程不再执行

第二种:即超时时间,单位为ms,若没有线程唤醒,那么到了这个时间段,就不再进行等待了;

第三种:即纳秒级别的时间,由于系统精度,可能无法准确执行,且很少使用;

4.2notify唤醒wait

1.若两个锁对象调用的这两个方法,如果锁对象是不一样的,那么就无法进行唤醒;

2.若右两个锁对象调用wait,那么调用notify的锁对象,要唤醒对应的wait,若两个wait的锁对象是一样的,那么随机唤醒

3.notifyAll用于唤醒对应线程上的所有线程;注意:被唤醒的线程中,多个wait的执行,导致锁的竞争,那么此时那个限制性,那个后执行是不确定的;

4.3wait和sleep的区别

1.这里的wait也是带有时间的超时时间的wait方法,sleep也是一样的带有时间的,那么就是到时间就会继续执行;

2.wait和sleep虽然时间没有到,但是任然可以被提前唤醒;wait是通过notify进行唤醒,而sleep是通过interrupt进行提前唤醒;

3.使用wait,是不知道等待的时间的前提下使用的,所谓的超时时间只不过是一个“兜底时间”,而sleep是要知道时间的前提下才使用,虽然也能够被提前唤醒,但是这个是一个不正常的业务流程,(异常唤醒,这是说明代码出现了BUG了)

📚️5.总结

💬💬小编本期讲解了关于wait的使用方法,对应的notify的操作,以及线程饿死的场景演示;当然还有在使用wait和notify时的使用注意事项,还附上了对应代码供uu们参考参考~~~

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

                                               😊😊  期待你的关注~~~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com