Java多线程_0x5_
多线程篇五——wait和notify
如笔者理解有误,欢迎交流指正⭐
线程的执行先后顺序难以预料【抢占式执行】,但是实际开发中我们会需要掌握当下线程的执行顺序.
这就是wait和notify的作用.【都是Object方法即随便定义一个对象豆可以使用wait和notify】
wait()方法
wait执行过程
1.释放当前的锁
2.让线程进入阻塞
3.当线程被唤醒的时候重新获取到锁
上代码
1 | public class Demo15 { |
运行发现wait一直处于等待状态
1
tips
wait搭配synchronized使用,synchronized加锁给对象头进行标记
wait结束等待的条件
其他线程调用该对象的notify方法
wait等待超时(timeout用来指定等待时间)
其他线程调用该等待线程的interrupted方法,抛出InterruptedException异常
wait和sleep的对比
共同点
让线程在一段时间里不执行.【wait用于线程间通信(生产者-消费者模型) sleep用于线程阻塞(延迟操作)】
不同点
1.wait()可通过notify()唤醒,sleep()通过Interrupt()唤醒
2.使用wait()时没有设置最大等待时间,而sleep()是在知道最大时限的情况下使用(通过异常唤醒,说明程序应该是出现特殊情况了).
3.wait()搭配synchronized使用,sleep()不用.
4.wait()是Object的方法,sleep()是Thread的静态方法.
5.wait()方法会释放锁,sleep()不会.
notify()方法
此时我们的notify()方法就担起了唤醒wait()方法的大任(唤醒等待的线程).
tips
notify()要在同步方法或同步块中调用.它会通知可能等待该对象对象锁的其他线程,使得它们重新获取对象锁.
如果有多个线程等待,有线程调度器随机挑选一个wait状态的线程[【无先来后到】
调用notify()方法后不会立即释放对象锁,要等到执行notify()方法的线程将程序执行完之后【退出同步代码块】才会释放对象锁.
notify唤醒线程过程
1.创建 WaitTask 类, 对应一个线程, run 内部循环调用 wait.
2.创建 NotifyTask 类, 对应另一个线程, 在 run 内部调用一次 notify 注意, WaitTask 和 NotifyTask 内部持有同一个 Object locker.
3.WaitTask 和 NotifyTask 要想配合 就需要搭配同一个 Object.
1 | public class Demo16 { |
notifyAll()方法
顾名思义哈 notifyAll()可以唤醒所有方法>
注意
唤醒的这些方法在等待(wait)返回时重新获取锁产生锁竞争,但实际这些锁是串行执行的【锁被哪个线程先获取是不确定的】
区别notify()和notifyAll()
1.唤醒一个/都唤醒
2.没有锁竞争/产生锁竞争
对比可发现notify()比notifyAll()好控制 发生错误的概率更低