• Java多线程之生产者与消费者


    1、仓库

     1 package com.cn.donleo.thread.house;
     2 
     3 /**
     4  * @author liangd
     5  * date 2020-11-02 10:36
     6  * code 仓库
     7  */
     8 public class StoreHouse {
     9     /**
    10      * 仓库容纳数量
    11      */
    12     public static int count = 10;
    13     /**
    14      * 判断仓库是否有东西
    15      */
    16     public static Boolean isNull =false;
    17     public static final Object OBJECT = new Object();
    18 }

    2、生产者

     1 package com.cn.donleo.thread.house;
     2 
     3 /**
     4  * @author liangd
     5  * date 2020-11-02 10:40
     6  * code
     7  */
     8 public class Productor extends Thread {
     9     /**
    10      * 对于生产者来说,我们需要以下几个步骤:
    11      * 判断生产者是否还可以生产,因为规定一天只生产10个,可以则继续,不能则返回
    12      * 第一:判断仓库里面是否有还有物品
    13      * 第二:如果有,则线程等待,即等待消费者来拿
    14      * 第三:如果没有,则生产物品,并提示仓库里面有东西,并呼叫消费者
    15      * 生产者的run方法,一直向仓库添加元素
    16      */
    17     @Override
    18     public void run() {
    19         while (true) {
    20             //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西,
    21             //所以不能用new WareHouse(),来创建对象
    22             synchronized (StoreHouse.OBJECT) {
    23                 if (StoreHouse.count == 0) {
    24                     break;
    25                 } else {
    26                     if (!StoreHouse.isNull) {
    27                         System.out.println(getName() + "生产者生产产品");
    28                         StoreHouse.isNull = true;
    29                         /*
    30                            一、notify和notifyAll的区别
    31                               主要区别:notify和notifyAll之间的关键区别在于notify()只会唤醒一个线程,
    32                               而notifyAll方法将唤醒所有线程。
    33 
    34                            二、何时在Java中使用notify和notifyAll?
    35                              1、如果所有线程都在等待相同的条件,并且一次只有一个线程可以从条件变为true,
    36                                 则可以使用notify over notifyAll。
    37                              2、在这种情况下,notify是优于notifyAll 因为唤醒所有这些因为我们知道只有一个线程会受益
    38                                 而所有其他线程将再次等待,所以调用notifyAll方法只是浪费CPU。
    39                              3、虽然这看起来很合理,但仍有一个警告,即无意中的接收者吞下了关键通知。
    40                                 通过使用notifyAll,我们确保所有收件人都会收到通知
    41 
    42                          */
    43                         StoreHouse.OBJECT.notifyAll();
    44                     } else {
    45                         try {
    46                             /*
    47                                一、notify、 notifyAll、wait属于Object里面的方法
    48                                二、sleep和wait有什么区别
    49                                  1、Sleep是属于Thread类的静态方法,wait属于Object的方法。
    50                                  2、最主要是sleep方法没有释放锁,而是放弃CPU的调度。而wait方法释放了锁,
    51                                     使得其他线程可以进入同步控制块或者方法。
    52                                  3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,
    53                                     而sleep可以在任何地方使用,synchronized(x){x.notify()//或者wait()}
    54                                  4、sleep必须捕获异常,wait也需要捕获异常,notify和notifyAll不需要捕获异常
    55                                  5、使用wait,notify可以达到线程之间的通信目的
    56                             */
    57                             /*
    58                               1.使用sleep方法,在毫秒值结束后,线程睡醒进入到Runnable/blocked状态
    59                               2.使用wait方法,wait方法如果在毫秒值结束后,还没有被notify唤醒,就会自动醒来,
    60                                 线程睡醒进入到Runnable/blocked状态
    61                              */
    62                             StoreHouse.OBJECT.wait();
    63 //                            StoreHouse.OBJECT.wait(500);
    64                         } catch (InterruptedException e) {
    65                             e.printStackTrace();
    66                         }
    67                     }
    68                 }
    69             }
    70         }
    71     }
    72 }

    3、消费者

     1 package com.cn.donleo.thread.house;
     2 
     3 /**
     4  * @author liangd
     5  * date 2020-11-02 10:40
     6  * code
     7  */
     8 public class Consumer extends Thread {
     9     /**
    10      * 1.while(true)
    11      * 2.synchronized ()
    12      * 3.判断生产者是否已经停止生产了,如果已经停止了,就跳出,如果没有,则可以继续去仓库拿
    13      * 4.判断仓库是否有物品,如果有,则直接拿。拿了就需要讲次数减一,然后呼叫生产者生产
    14      * 5.如果没有,则等待生产者生产
    15      */
    16     @Override
    17     public void run() {
    18         while (true) {
    19             //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西,
    20             //所以不能用new WareHouse(),来创建对象
    21             synchronized (StoreHouse.OBJECT) {
    22                 try {
    23                     //休眠0.5s
    24                     Thread.sleep(500);
    25                 } catch (InterruptedException e) {
    26                     e.printStackTrace();
    27                 }
    28                 if (StoreHouse.count == 0) {
    29                     break;
    30                 } else {
    31                     if (StoreHouse.isNull) {
    32                         System.out.println(getName() + "消费者可以拿产品了");
    33                         StoreHouse.isNull = false;
    34                         StoreHouse.OBJECT.notifyAll();
    35                         StoreHouse.count--;
    36                     } else {
    37                         try {
    38                             StoreHouse.OBJECT.wait();
    39                         } catch (InterruptedException e) {
    40                             e.printStackTrace();
    41                         }
    42                     }
    43                 }
    44             }
    45         }
    46     }
    47 }

    4、测试类

     1 package com.cn.donleo.thread.house;
     2 
     3 /**
     4  * @author liangd
     5  * date 2020-11-02 10:56
     6  * code 生产者消费者测试类
     7  */
     8 public class TestProductorCunsumer {
     9     public static void main(String[] args){
    10         //线程1
    11         Productor productor = new Productor();
    12         productor.setName("生产者");
    13         //线程2
    14         Consumer consumer1 = new Consumer();
    15         consumer1.setName("A消费者");
    16         //线程3
    17         Consumer consumer2 = new Consumer();
    18         consumer2.setName("B消费者");
    19         productor.start();
    20         consumer1.start();
    21         consumer2.start();
    22     }
    23 }
    作者:donleo123
    本文如对您有帮助,还请多推荐下此文,如有错误欢迎指正,相互学习,共同进步。
  • 相关阅读:
    Oracle 对比insert和delete操作产生的undo
    MySQL 详细解读undo log :insert undo,update undo
    什么是关系型数据库?
    Greenplum 常用数据库管理语句,sql工具
    Greenplum常用的gp_toolkit & pg_catalog监控语句
    Greenplum 与 PostgreSQL 修改元数据(catalog)的方法 allow_system_table_mods
    Greenplum 6 新功能 在线扩容工具GPExpand (转载)
    Pivotal Greenplum 6.0 新特性介绍
    数据库 Hash Join的定义,原理,算法,成本,模式和位图
    Mycat 全局系列号(转载)
  • 原文地址:https://www.cnblogs.com/donleo123/p/14069960.html
Copyright © 2020-2023  润新知