当前位置:网站首页>【多线程】线程通信调度、等待集 wait() 、notify()
【多线程】线程通信调度、等待集 wait() 、notify()
2022-06-27 15:44:00 【51CTO】
目录
对象等待集来干预线程的调度
wait 和 notify 为了处理线程调度随机性的问题。
还是那句话,多线程的调度,因为它的随机性,就导致代码谁先执行,谁后执行,存在太多的变数。
而我们程序员是不喜欢随机性,我们喜欢确定的东西。
需要能够让线程彼此之间,有一个固定的顺序。
举个例子:打篮球
篮球里面有一个典型的操作:传球,上篮。
那么我们肯定得先传球,再上篮。需要两个队员的相互配合。
两个队员也就是两个线程。
如果是先做个上篮动作,但是球没到,也就上了个寂寞。
一般最稳的方法,都是先传球再上篮。
像这样的顺序,在我们实际开发中也是非常需要的。因此我们就需要有手段去控制!
之前讲到的 join 也是一种控制顺序的方式,但是 join更倾向于控制线程结束。因此 join 是有使用的局限性。
就不像 wait 和 notify 用起来更加合适。
wait 方法
其实wait()方法就是使线程停止运行。
方法wait()的作用是使当前执行代码的线程进行等待,wait( )方法是Object类的方法,该方法是用来将当前线程置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。wait( )方法只能在同步方法中或同步块中调用。如果调用wait()时,没有持有适当的锁,会抛出异常。- wait( )方法执行后,当前线程释放锁,并一直处于等待通知状态, 直到其他线程唤醒该线程后与其它线程竞争重新获取锁。


调用 wait 方法的线程,就会陷入阻塞,阻塞到有其它线程通过 notify 来通知。

notify 方法
一个线程执行到object.wait()之后就一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个方法唤醒的方法notify()。
notify方法就是使停止的线程继续运行
方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

根据这种机制我们可以编排多个线程的顺序

notifyAll 方法
前面说的 wait 和 notify 都是针对同一个对象来操作。
例如:
现在有
一个对象 o,被 10个线程调用了o.wait。
此时10 个 线程都是阻塞状态。
如果调用了o.notify,就会把10个线程中的一个给唤醒
【随机唤醒:不确定下一个被唤醒的线程是哪一个】被唤醒的线程就会继续往下执行。其他线程仍处于阻塞状态。
如果
调用的 o.notifyAll,就会把所有的线程全部唤醒wait 在被唤醒之后,会重新尝试获取到锁,这个过程就会发生竞争唤醒所有的线程,都去抢锁。
抢到的,才可以继续往下执行。
没抢到的线程,继续等待,等待下一次的 notifyAll。**
wait方法总结
wait( )的作用是让当前线程进入等待状态,同时,wait( )也会让当前线程释放它所持有的锁。
直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,使当前线程被唤醒(进入“就绪状态”)
- notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程
notify()是唤醒单个线程
notifyAll()是唤醒所有的线程, 然后这些线程再去竞争那同一把锁。(不建议使用notifyAll )
wait(long timeout)让当前线程处于“等待(阻塞)状态”
“直到其他线程调用此对象的notify()方法或 notifyAll() 方法
或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)
总结: wait() 的工作过程就是:
释放对象锁(所以必须有一个锁才能正常执行)等待通知(时间可能会长, 因为不参与后序锁的竞争直到有其他线程调用该对象的notify()去唤醒该线程)收到通知后 尝试重新获取对象锁 继续往下执行
特别注意
wait() 和 notify() 操作必须放在 synchronized 的代码块之内使用否则会报异常调用wait() 和 notify() 的对象必须是同一个对象 才能起到等待和唤醒操作更准确的说: 因为wait 和 notify 要在 synchronized 的代码块内 所以上锁的对象也应该和 wait() 和 notify() 的对象必须是同一个对象 这样就是4个对象得保持一致
notify方法总结
- 一个线程执行到object.wait()之后就一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个方法唤醒的方法notify()。
- notify方法就是使停止的线程继续运行。
- 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。
- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
注意:
唤醒线程不能过早,如果在还没有线程在等待中时,过早的唤醒线程,这个时候就会出现先唤醒,在等待的效果了。
这样 就没有必要在去运行wait方法了。导致竞态条件问题
运行结果:

竞态条件问题
竞态条件问题当一个 t 线程执行了wait()方法释放了对象锁之后 另外一个 t1 线程获取了锁然后立即执行了notify()方法区通知 t 线程 但是 t 线程还没有执行到等待通知的那段代码 所以这个通知就错过了 这样线程 t 就会一直等待下去 这就是一个竞态条件问题- 为了解决和
避免这个问题 事实上当我们在执行wait() 操作的时候 释放锁和等待接收通知是处于一个原子性质上执行的 最后才执行尝试重新获取锁
wait与sleep的对比
- wait用于线程之间的通信 sleep用于让线程阻塞一段时间
- wait之前必须要有锁 wait之后会释放锁 等被唤醒之后再重尝试请求锁
- sleep是无视锁的存在的 即不会要求有锁 也不会去释放锁
- wait是object的方法
- sleep是thread的静态方法
- 唯一相同点就是都可以让线程放弃执行一段时间
边栏推荐
- Leetcode daily practice (Yanghui triangle)
- Bit. Store: long bear market, stable stacking products may become the main theme
- C language teacher workload management system
- The interview lasted for half a year. Last month, I successfully got Alibaba p7offer. It was all because I chewed the latest interview questions in 2020!
- 鸿蒙发力!HDD杭州站·线下沙龙邀您共建生态
- The array of C language is a parameter to pass a pointer
- #yyds干货盘点# 解决剑指offer:二叉树中和为某一值的路径(三)
- What is the level 3 password complexity of ISO? How often is it replaced?
- Sigkdd22 | graph generalization framework of graph neural network under the paradigm of "pre training, prompting and fine tuning"
- If you want to use DMS to handle database permissions, can you only use Alibaba cloud ram accounts (Alibaba cloud RDS)
猜你喜欢

守护雪山之王:这些AI研究者找到了技术的新「用武之地」

3.4 fixed number of cycles II

Smart wind power | Tupu software digital twin wind turbine equipment, 3D visual intelligent operation and maintenance

Weekly snapshot of substrate technology 20220411

Hierarchical clustering and case analysis

A distribution fission activity is more than just a circle of friends!

List to table

字节跳动埋点数据流建设与治理实践

等保三级密码复杂度是多少?多久更换一次?

【牛客刷题】NowCoder号称自己已经记住了1-100000之间所有的斐波那契数。 为了考验他,我们随便出一个数n,让他说出第n个斐波那契数。如果第n个斐波那契大于6位则只取后6位。
随机推荐
Julia constructs diagonal matrix
Data center table reports realize customized statistics, overtime leave summary record sharing
QT audio playback upgrade (7)
数组表示若干个区间的集合,请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。【LeetCodeHot100】
Annual comprehensive analysis of China's audio market in 2022
Yyds dry inventory solution sword finger offer: a path with a certain value in the binary tree (3)
PolarDB-X现在版本的开源兼容什么?mysql8?
一场分销裂变活动,不止是发发朋友圈这么简单!
【Pygame小游戏】这款“吃掉一切”游戏简直奇葩了?通通都吃掉嘛?(附源码免费领)
Practice of constructing ten billion relationship knowledge map based on Nebula graph
[pyGame games] this "eat everything" game is really wonderful? Eat them all? (with source code for free)
Principle Comparison and analysis of mechanical hard disk and SSD solid state disk
Yyds dry inventory brief chrome V8 engine garbage collection
华为云首次解读云原生2.0十大典型架构,加速构建现代化应用
A distribution fission activity is more than just a circle of friends!
关于#mysql#的问题:问题遇到的现象和发生背景
The two trump brand products of Langjiu are resonating in Chengdu, continuously driving the consumption wave of bottled liquor
Redis Series 2: data persistence improves availability
Hongmeng makes efforts! HDD Hangzhou station · offline salon invites you to build ecology
Open source 23 things shardingsphere and database mesh have to say