您的位置 首页 java

死磕Java多线程并发第二天——wait()、notify()、notifyAll()

锁池和等待池

 wait() ,notifyAll(),notify() 三个方法都是Object类中的方法。学习他们之前先要了解俩个概念。java中,每个对象都有两个池,锁(monitor)池和等待池。
 

锁池 : 假设 线程 A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个 synchronized 方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。

等待池: 假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池。

notify()、notifyAll()、wait()

notify() : 通知一个在对象上等待的线程,由WAITING状态变为B lock ING状态,从等待队列移动到同步队列,等待CPU调度获取该对象的锁,当该线程获取到了对象的锁后,该线程从wait()方法返回。

notifyAll() : 通知所有等待在该对象上的线程,由WAITING状态变为BLOCKING状态,等待CPU调度获取该对象的锁。

wait() : 调用该方法的线程进入WAITING状态,并将当前线程放置到对象的等待队列,只有等待另外线程的通知或被中断才会返回,需要注意,调用wait()方法后,会释放对象的锁。

wait( long ) : 超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。

wait(long,int) : 对于超时时间更细力度的控制,可以达到 纳秒

简单的例子:

 等待通知机制,是指一个线程A调用了对象lock的wait()方法进入等待状态,而另一个线程B调用了对象lock的notify()或者notifyAll()方法,线程A收到通知后从对象lock的wait()方法返回,进而执行后续操作。上述两个线程通过对象lock来完成交互,而对象上的wait()和notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
 

———————

Wait类释放锁

唤醒线程

main结果

注意

  1. wait()、notify/notifyAll() 方法是Object的本地final方法,无法被重写。
  2. wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。
  3. notify/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁,锁的释放要看代码块的具体执行情况。所以在编程中,尽量在使用了notify/notifyAll() 后立即退出临界区,以唤醒其他线程 。
  4. wait() 需要被try catch包围,中断也可以使wait等待的线程唤醒。
  5. notify 和wait 的顺序不能错,如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的。
  6. notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对 多线程 管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。
  7. 多线程中要测试某个条件的变化,要使用 while 。只有当前值满足需要值的时候,线程才可以往下执行,所以,必须使用while 循环阻塞。注意,wait() 当被唤醒时候,只是让while循环继续往下走.如果此处用if的话,意味着if继续往下走,会跳出if语句块。但是,notifyAll 只是负责唤醒线程,并不保证条件,所以需要手动来保证程序的逻辑。
  8. wait方法释放锁,notify不释放锁。
  9. 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

———————

文章来源:智云一二三科技

文章标题:死磕Java多线程并发第二天——wait()、notify()、notifyAll()

文章地址:https://www.zhihuclub.com/194025.shtml

关于作者: 智云科技

热门文章

网站地图