首页 > 编程语言 > 详细

多线程总结

时间:2020-09-24 18:36:13      阅读:61      评论:0      收藏:0      [点我收藏+]

notify 和 notifyAll 的区别:

青铜玩家会一脸纯真的看着面试官,就是唤醒一个和唤醒一堆啊,但它两真正的区别是 notifyAll 调用后,会把所有在 Wait Set 中的线程状态变成 RUNNABLE 状态,然后这些线程再去竞争锁,获取到锁的线程为 Run 状态,没有获取到锁的线程进入 Entry Set 集合中变成 Block 状态,它们只需要等到上个线程执行完或者 wait 就可以再次竞争锁而无需 notify ; 而 notify 方法只是照规则唤醒 Wait Set 中的某一个线程,其它的线程还是在 Wait Set 中。

为什么 wait 要写在 while 循环中是因为 wait 是释放了锁,然后阻塞,等到下次唤醒的时候,在多个生产者多个消费者的情况下,有可能是被 “同类” 唤醒的,所以需要再去检查下状态是否正确。
所以所有的java书籍都会建议开发者永远都要把wait()放到循环语句里面。

wait, notify notifyAll 的使用方式:

Java中规定,在调用者三个方法时,当前线程必须获得对象锁。因此就得配合synchronized关键字来使用

为什么 这几个方法在 Object 上,而不是在 Thread 上

在synchronized拿到对象锁之后,synchronized代码块或者方法中,必定是会持有对象锁的,因此就可以使用wait()或者notify()。
通过上述使用方法,我们也能很好理解为什么这几个方法是在Object上而不是在Thread上。因为每个对象都可以作为synchronized锁的对象,因此wait、notify等必须和对象关联才能配合synchronized使用。

api 基本含义

wait 线程自动释放占有的对象锁,并等待notify。
notify 随机唤醒一个正在wait当前对象的线程,并让被唤醒的线程拿到对象锁
notifyAll 唤醒所有正在wait当前对象的线程,但是被唤醒的线程会再次去竞争对象锁。因为一次只有一个线程能拿到锁,所有其他没有拿到锁的线程会被阻塞。推荐使用。

为什么要避免调用notifyAll

一句话解释就是之所以我们应该尽量使用notifyAll()的原因就是,notify()非常容易导致死锁。
当然notifyAll并不一定都是优点,毕竟一次性将Wait Set中的线程都唤醒是一笔不菲的开销,如果你能handle你的线程调度,那么使用notify()也是有好处的。

为什么需要在同步方法中调用

任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
JVM基于多线程,默认情况下不能保证运行时线程的时序性

线程调用通知的 监视器 必须和 当前现场持有的监视器为同一个,否则将抛出 IllegalStateException

参考资料:

https://blog.csdn.net/qq_35598736/article/details/108431422
https://www.cnblogs.com/noteless/p/10394054.html
https://www.jianshu.com/p/25e243850bd2?appinstall=0
https://www.cnblogs.com/keyi/p/11987288.html

尤其建议阅读:
https://www.jianshu.com/p/25e243850bd2?appinstall=0
https://blog.csdn.net/qq_35598736/article/details/108431422

多线程总结

原文:https://www.cnblogs.com/fancyBrain/p/13720829.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!