zoukankan      html  css  js  c++  java
  • 多线程---阻塞队列

    阻塞队列的基本使用:

    常见的阻塞队列有ArrBlockingQueue和LinkedBlockQueue

    下面是它们的继承结构:

    •  ArrayBlockingQueue: 底层是数组,有界
    • LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值

    由Blockqueue的继承机制可以看出其实他们就是一个单列集合,所以集合中的方法他们是可以使用的:

    • put(anObject): 将参数放入队列,如果放不进去会阻塞
    • take(): 取出第一个数据,取不到会阻塞
    • 在创建Blockqueue的时候构造方法中填一个int型数字代表该阻塞队列最多可以容乃多少个元素

    阻塞简单代码如下:

     1 public class Demo02 {
     2     public static void main(String[] args) throws Exception {
     3         // 创建阻塞队列的对象,容量为 1
     4         ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
     5 
     6         // 存储元素
     7         arrayBlockingQueue.put("汉堡包");
     8 
     9         // 取元素
    10         System.out.println(arrayBlockingQueue.take());
    11         System.out.println(arrayBlockingQueue.take()); // 取不到会阻塞
    12 
    13         System.out.println("程序结束了");//程序不会执行到这里
    14     }
    15 }

    下面写一个案例有助于理解:

    • 案例需求

    生产者类(Cooker):实现Runnable接口,重写run()方法,设置线程任务

       1.构造方法中接收一个阻塞队列对象

       2.在run方法中循环向阻塞队列中添加包子

       3.打印添加结果

    消费者类(Foodie):实现Runnable接口,重写run()方法,设置线程任务

       1.构造方法中接收一个阻塞队列对象

       2.在run方法中循环获取阻塞队列中的包子

       3.打印获取结果

    测试类(Demo):里面有main方法,main方法中的代码步骤如下

       1.创建阻塞队列对象

       2.创建生产者线程和消费者线程对象,构造方法中传入阻塞队列对象

       3.分别开启两个线程

    代码实现:

     1 public class Cooker extends Thread {
     2 
     3     private ArrayBlockingQueue<String> bd;
     4 
     5     public Cooker(ArrayBlockingQueue<String> bd) {
     6         this.bd = bd;
     7     }
     8 //    生产者步骤:
     9 //            1,判断桌子上是否有汉堡包
    10 //    如果有就等待,如果没有才生产。
    11 //            2,把汉堡包放在桌子上。
    12 //            3,叫醒等待的消费者开吃。
    13 
    14     @Override
    15     public void run() {
    16         while (true) {
    17             try {
    18                 bd.put("汉堡包");
    19                 System.out.println("厨师放入一个汉堡包");
    20             } catch (InterruptedException e) {
    21                 e.printStackTrace();
    22             }
    23         }
    24     }
    25 }
    26 
    27 public class Foodie extends Thread {
    28     private ArrayBlockingQueue<String> bd;
    29 
    30     public Foodie(ArrayBlockingQueue<String> bd) {
    31         this.bd = bd;
    32     }
    33 
    34     @Override
    35     public void run() {
    36 //        1,判断桌子上是否有汉堡包。
    37 //        2,如果没有就等待。
    38 //        3,如果有就开吃
    39 //        4,吃完之后,桌子上的汉堡包就没有了
    40 //                叫醒等待的生产者继续生产
    41 //        汉堡包的总数量减一
    42 
    43         //套路:
    44         //1. while(true)死循环
    45         //2. synchronized 锁,锁对象要唯一
    46         //3. 判断,共享数据是否结束. 结束
    47         //4. 判断,共享数据是否结束. 没有结束
    48         while (true) {
    49             try {
    50                 String take = bd.take();
    51                 System.out.println("吃货将" + take + "拿出来吃了");
    52             } catch (InterruptedException e) {
    53                 e.printStackTrace();
    54             }
    55         }
    56 
    57     }
    58 }
    59 
    60 public class Demo {
    61     public static void main(String[] args) {
    62         ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);
    63 
    64         Foodie f = new Foodie(bd);
    65         Cooker c = new Cooker(bd);
    66 
    67         f.start();
    68         c.start();
    69     }
    70 }

    注意:运行结果中会出现两次吃两次做,原因是:吃喝做的代码使我们自己写的并没有锁,程序执行是虽然已经做了或者吃了

    但是在运行到做了或者吃了的时候CPU可能就会执行另一个线程,导致重复,但是实际上是做一个吃一个,做一个吃一个

    迎风少年
  • 相关阅读:
    实验四——多分支结构及本章总结
    实验五——循环结构学习总结
    实验12——指针的基础应用 2
    实验11——指针的基础应用
    实验十——一维数组的定义及引用
    实验九——基本数据类型存储及应用总结
    实验八——函数定义及调用总结
    实验七——函数定义及调用总结
    实验六——循环结构程序练习总结
    实验五——循环结构学习总结
  • 原文地址:https://www.cnblogs.com/ZYH-coder0927/p/13519331.html
Copyright © 2011-2022 走看看