【进阶】 wait sleep
2021-08-05 本文已影响0人
lconcise
-
wait sleep 区别
不同:
- wait会释放锁,而sleep不会释放锁
- wait只能在同步方法和同步代码块中使用,而sleep任何地方都可以
相同点:都会让渡CPU执行时间,等待再次调度
-
wait为什么要在同步块中使用?
1. lost wake up 问题
如果wait 不在同步方法或者同步代码块中使用,运行代码会直接报错。
public static void main(String[] args) throws Exception{
Object obj = new Object();
obj.wait();
}
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at top.lconcise.practice.demo.NodeDemo.main(NodeDemo.java:11)
事情得从一个多线程编程里面臭名昭著的问题"Lost wake-up problem"说起。
这个问题并不是说只在Java语言中会出现,而是会在所有的多线程环境下出现。
生产者消费之的代码:
生产者伪代码:
count+1;
notify();
消费者伪代码:
while(count<=0){
wait()
}
count--
image.png
解决该问题,就需要保证这一系列操作的原子性,在同步方法或同步代码中执行,可以保证原子性。
2. wait notify 原理
- 调用wait() 首先会获取监视器锁,获得成功后,会让线程进入等待状态进入等待队列并且释放锁;
- 然后当其他线程调用notify或者notifyall以后,会选择从等待队列中唤醒任意一个线程
- 而执行完notify方法以后,并不会立马唤醒线程,原因是当前线程仍然持有这把锁,处于等待状态的线程无法获得锁。必须要等到当前的线程执行完按monitorexit指令之后,也就是被释放之后,处于等待队列的线程就可以开始竞争锁了。
所以 wait 方法要做两件事
- 释放当前对象的锁
- 使得当前线程进入阻塞队列
而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁,只在synchronized里面,才能明确锁。
-
为什么sleep 不用在同步代码块中?
放在同步块中是为了多线程并发处理,大家按照顺序依次合理干活,不要造成死锁饥饿现象,但是sleep()方法就是想让当前线程进入阻塞状态,不要干活,我也不释放我已经拥有的锁,等到sleep()的时间到了,我再进入就绪态,等待cpu派活给我。sleep根本就不存在多线程并发访问问题,所以就不需要放在同步块中。
-
为什么wait方法在object类中,sleep方法在Thread类中?
wait方法是让当前线程释放锁。然后让别的线程继续竞争。阻塞线程
notify通知 唤醒一个阻塞的线程 随机通知一个
这些都应该属于资源锁的动作,而作为锁,java中锁一般锁谁?锁的是对象,因为对象是资源,是我们需要操作的实体,而Object是所有对象的父类
sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定。