线程间通信Object的waitnotify

Dear 丶 2022-09-11 01:18 239阅读 0赞

wait/notify等待通知方式

等待通知机制就是将处于等待状态的线程将由其它线程发出通知后重新获取CPU资源,继续执行之前没有执行完的任务。最典型的例子生产者–消费者模式

image-20210903132410512

生产者想要在队列中添加产品,消费者需要从队列中取出产品,如果队列为空,消费者应该等待生产者添加产品后才进行消费,队列为满时,生产者需要等待消费者消费一部分产品后才能继续生产。队列可以认为是java模型里的临界资源,生产者和消费者认为是不同的线程,它们需要交替的占用临界资源来进行各自方法的执行,所以就需要线程间通信。

等待/通知机制主要提供了三个方法用于线程间的通信

wait()当前线程释放锁并进入等待(阻塞)状态

notify()唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁

notifyAll()唤醒所有正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁

等待/通知机制是指一个线程A调用了对象Object的wait()方法进入等待状态,而另一线程B调用了对象Object的notify()或者notifyAll()方法,当线程A收到通知后就可以从对象Object的wait()方法返回,进而执行后序的操作。线程间的通信需要对象Object来完成,对象中的wait()、notify()、notifyAll()方法就如同开关信号,用来完成等待方和通知方的交互。

等待/通知的相关方法:

image-20210910103119062

实例

场景—两个线程,一个线程对当前数值加1,另一个线程对当前数值减1,一共执行10次

假设这个共享变量的初始值为0,一个线程t1对值+1,另一个线程t2对值-1.

  1. package com.dongguo.concurrent.waitnotify;
  2. /** * @author Dongguo * @date 2021/9/3 0003-13:15 * @description: 生产者消费者 * 场景---两个线程,一个线程对当前数值加1,另一个线程对当前数值减1,一共执行10次 * 假设这个共享变量的初始值为0,一个线程对值+1,另一个线程对值-1. */
  3. public class ThreadWaitNotifyDemo {
  4. public static void main(String[] args) {
  5. Number number = new Number();
  6. new Thread(() -> {
  7. for (int i = 0; i < 10; i++) {
  8. number.incry();
  9. }
  10. }, "t1").start();
  11. new Thread(() -> {
  12. for (int i = 0; i < 10; i++) {
  13. number.decry();
  14. }
  15. }, "t2").start();
  16. }
  17. }
  18. class Number {
  19. private int count;
  20. public synchronized void incry() {
  21. if (count != 0) {
  22. try {
  23. this.wait();
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. count++;
  29. System.out.println(Thread.currentThread().getName() + "加一成功,count值为:" + count);
  30. this.notifyAll();
  31. }
  32. public synchronized void decry() {
  33. if (count == 0) {
  34. try {
  35. this.wait();
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. count--;
  41. System.out.println(Thread.currentThread().getName() + "减一成功,count值为:" + count);
  42. this.notifyAll();
  43. }
  44. }

运行结果:

  1. t1加一成功,count值为:1
  2. t2减一成功,count值为:0
  3. t1加一成功,count值为:1
  4. t2减一成功,count值为:0
  5. t1加一成功,count值为:1
  6. t2减一成功,count值为:0
  7. t1加一成功,count值为:1
  8. t2减一成功,count值为:0
  9. t1加一成功,count值为:1
  10. t2减一成功,count值为:0
  11. t1加一成功,count值为:1
  12. t2减一成功,count值为:0
  13. t1加一成功,count值为:1
  14. t2减一成功,count值为:0
  15. t1加一成功,count值为:1
  16. t2减一成功,count值为:0
  17. t1加一成功,count值为:1
  18. t2减一成功,count值为:0
  19. t1加一成功,count值为:1
  20. t2减一成功,count值为:0

调用wait()、notify()以及notifyAll()时需要注意的细节,。
1)使用wait()、notify()和notifyAll()时需要先对调用对象加锁。
2)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的
等待队列。
3)notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或
notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。
4)notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()
方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为
BLOCKED。
5)从wait()方法返回的前提是获得了调用对象的锁。
从上述细节中可以看到,等待/通知机制依托于同步机制,其目的就是确保等待线程从
wait()方法返回时能够感知到通知线程对变量做出的修改。

发表评论

表情:
评论列表 (有 0 条评论,239人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线通信

    1、什么是多线程之间通信 多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 于是我们引出了等待唤醒机制:

    相关 线通信Objectwaitnotify

    wait/notify等待通知方式 等待通知机制就是将处于等待状态的线程将由其它线程发出通知后重新获取CPU资源,继续执行之前没有执行完的任务。最典型的例子生产者–消费者

    相关 线通信

    为什么需要线程通讯 线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这

    相关 线通信

      https://www.cnblogs.com/hapjin/p/5492619.html 通常可用把并行程序理解为一组相互独立的、能够发关和接收消息的组件,这也称为角

    相关 线通信

    线程和线程之间不是独立的个体,它们彼此之间可以互相通信和协作。 线程通信就是在线程之间传递信息,保证他们能够协同工作。在线程间进行通信后,系统之间的交互性会更强大,在大大提高

    相关 线通信

    注意: 必须在同步方法中使用wait和notify方法,因为执行wait和notify的前提条件是必须持有同步方法(或块)的monitor的所有权,否则将会抛出异常

    相关 线通信

    典型例子就是生产者-消费者模式,仓库为空时,消费者无法从仓库调动产品,只能wait,直到仓库有产品时被notify;仓库满了时,生产者则暂时停止生产(wait),直到仓库有空被