Java多线程——wait(),notify(),notifyAll()等待通知机制
这里所说的wait(),notify(),notifyAll()都是Object类的方法,线程Thread只不过是将这些方法进行了封装,实际调用的还是Object的方法。
wait():使线程停止运行,会释放对象锁。——痴汉方法
1、wait()方法会使当前线程调用该方法后进行等待,并且将该线程置入锁对象的等待队列
中,直到接到通知或被中断为止。
2、wait()方法只能在同步方法或同步代码块
中调用,如果调用wait()时没有适当的锁,会抛出异常。(必须要有一个锁对象
)
3、wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
4、wait()方法从运行态->阻塞态。
5、wait()之后的线程继续执行有两种方法
①调用该对象的notify()方法唤醒等待线程
②线程等待时调用interrupt()中断该线程
6、wait(long timeout):设置了最长等待时间——如果到了预计时间还未被唤醒,线程将继续执行。
notify():使停⽌的线程继续运⾏。
1、notify()方法也必须在同步方法或同步代码块
中调用,用来唤醒等待在该对象上的其他线程。如果有多个线程在等待,则任意挑选一个
线程唤醒。(不管是唤醒还是等待,都得有一个被锁定了的对象,所以都得在同步xx中
)
2、notify()方法执行后,唤醒线程不会立刻释放对象锁,要等待唤醒线程全部执行完毕后才释放对象锁。
notifyAll():唤醒所有在该对象上等待的线程
这几个函数的概念如上,已经说得很详细了,再强调一句:wait(),notify(),notifyAll()必须用于同步代码块或同步方法
中且必须是内建锁
(和monitor相关)
线程在什么情况下会出现阻塞?
1、调用sleep()方法,主动放弃占有的CPU,不会释放对象锁
2、调用阻塞式IO方法(read(),write()),在该方法返回前,线程阻塞
3、线程试图获取一个对象的monitor,但该monitor被其他线程所持有导致阻塞
4、线程等待某个通知,即调用wait(),释放对象锁
5、调用线程suspend(),将线程挂起,容易导致死锁,已被废弃
其实对于每个对象锁monitor都存在两个队列。就绪队列与阻塞队列。
阻塞队列:存放因为竞争monitor失败而被阻塞的线程,⼀个线程被wait后,也会进⼊阻塞队列,等待下⼀次被唤醒。
就绪队列:存放将要获得锁的队列,一个线程被唤醒后进入就绪队列竞争锁。(等待CPU的调度)