java多线程等待唤醒机制详细介绍

java多线程等待唤醒机制

一. 方法介绍

方法 说明
void wait() 线程等待,等待的过程中线程会释放锁,需要被其他线程调用notify方法将其唤醒,重新抢锁执行
void notify() 线程唤醒,一次唤醒一个等待线程;如果有多条线程等待,则随机唤醒一条等待线程
void notifyAll() 唤醒所有等待线程

二.等待唤醒案例分析(线程之间的通信)

要求:一个线程生产,一个线程消费,不能连续生产,不能连续消费 -> 等待唤醒机制(生产者,消费者)(线程之间的通信)

这里一包子铺与消费者之间关系举列

1. 生产者(包子铺)

包子铺负责生产包子

那么如何表示包子铺 --> 我们这里可以定义一个count变量 , 代表生产包子的数目 , 每次生产count++

2. 消费者

消费者负责消费包子 , 每次消费的过程中只需要打印消费了第多少个包子即可

3. 生产者与消费者的关系

问1. 那么我们如何来表示现在是否存在包子 , 是需要生产还是消费?

这里只需要再定义一个标识符flag , 用于判断即可 , 当flag为true则有包子调用生产者 , 反之调用消费者

问2. 我们该如何保证在生产到一半的时候 , cpu自动切换到消费?

很简单使用线程锁即可

问3. 如何保证生产一个 , 消费一个?

即使加锁我们也无法保证生产和消费同步

这里我们就需要使用到等待和唤醒方法了

三. 代码阐述

创建包子铺类

在该类中我们需要对getCount和setCount进行修改 , 使其对应成为消费和生产方法

   /*
      count和flag可以定义成包装类
      但是要记得给count和flag手动赋值
      不然对于本案例来说,容易出现空指针异常
    */
   public class BaoZiPu {
       //代表包子的count
       private int count;
       //代表是否有包子的flag
       private boolean flag;

       public BaoZiPu() {
       }

       public BaoZiPu(int count, boolean flag) {
           this.count = count;
           this.flag = flag;
       }

       /*
          getCount 改造成消费包子方法
          直接输出count
        */
       public void getCount() {
           System.out.println("消费了..............第"+count+"个包子");
       }

       /*
          setCount 改造成生产包子
          count++
        */
       public void setCount() {
           count++;
           System.out.println("生产了...第"+count+"个包子");
       }

       public boolean isFlag() {
           return flag;
       }

       public void setFlag(boolean flag) {
           this.flag = flag;
       }
   }

定义生产者类

生产线程 , 在循环中通过判断flag来决定是否生产 . 如果flag为true则已有包子不需要生产 , 设置该线程等待即可 , 反之没有包子则生产 , count+1 , 将flag改为false , 并唤醒消费线程

   public class Product implements Runnable{
       private BaoZiPu baoZiPu;

       public Product(BaoZiPu baoZiPu) {
           this.baoZiPu = baoZiPu;
       }

       @Override
       public void run() {
           while(true){

               try {
                   Thread.sleep(100L);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }

               synchronized (baoZiPu){
                   //1.判断flag是否为true,如果是true,证明有包子,生产线程等待
                   if (baoZiPu.isFlag()==true){
                       try {
                           baoZiPu.wait();
                       } catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       }
                   }

                   //2.如果flag为false,证明没有包子,开始生产
                   baoZiPu.setCount();
                   //3.改变flag状态,为true,证明生产完了,有包子了
                   baoZiPu.setFlag(true);
                   //4.唤醒消费线程
                   baoZiPu.notify();
               }
           }
       }
   }

消费者类

逻辑和生产者类似就不过多赘述

   public class Consumer implements Runnable{
       private BaoZiPu baoZiPu;

       public Consumer(BaoZiPu baoZiPu) {
           this.baoZiPu = baoZiPu;
       }

       @Override
       public void run() {
           while(true){

               try {
                   Thread.sleep(100L);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }

               synchronized (baoZiPu){
                   //1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
                   if (baoZiPu.isFlag()==false){
                       try {
                           baoZiPu.wait();
                       } catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       }
                   }

                   //2.如果flag为true,证明有包子,开始消费
                   baoZiPu.getCount();
                   //3.改变flag状态,为false,证明消费完了,没 有包子了
                   baoZiPu.setFlag(false);
                   //4.唤醒生产线程
                   baoZiPu.notify();
               }
           }
       }
   }

实现类

   public class Test01 {
       public static void main(String[] args) {
           BaoZiPu baoZiPu = new BaoZiPu();

           Product product = new Product(baoZiPu);
           Consumer consumer = new Consumer(baoZiPu);

           Thread t1 = new Thread(product);
           Thread t2 = new Thread(consumer);

           t1.start();
           t2.start();
       }
   }
相关推荐
向宇it4 分钟前
【从零开始入门unity游戏开发之——C#篇30】C#常用泛型数据结构类——list<T>列表、`List<T>` 和数组 (`T[]`) 的选择
java·开发语言·数据结构·unity·c#·游戏引擎·list
葡萄架子4 分钟前
Python中的logger作用(from loguru import logger)
java·前端·python
hakesashou9 分钟前
python怎么看矩阵维数
开发语言·python
daopuyun17 分钟前
GB/T34944-2017 《Java语言源代码漏洞测试规范》解读——安全功能
java·开发语言·安全
编程洪同学22 分钟前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
qh0526wy29 分钟前
pyqt5冻结+分页表
开发语言·python·qt
小小药32 分钟前
009-spring-bean的实例化流程
java·数据库·spring
hjxxlsx36 分钟前
探索 C++ 自定义函数的深度与广度
开发语言·c++
罗政1 小时前
PDF书籍《手写调用链监控APM系统-Java版》第12章 结束
java·开发语言·pdf
匹马夕阳1 小时前
详细对比JS中XMLHttpRequest和fetch的使用
开发语言·javascript·ecmascript