多线程---阻塞队列

阻塞队列的基本使用:

常见的阻塞队列有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可能就会执行另一个线程,导致重复,但是实际上是做一个吃一个,做一个吃一个

 

posted @ 2020-08-17 18:53  Joker-0927  阅读(192)  评论(0编辑  收藏  举报
// 侧边栏目录