多线程---阻塞队列
阻塞队列的基本使用:
常见的阻塞队列有ArrBlockingQueue和LinkedBlockQueue
下面是它们的继承结构:
- ArrayBlockingQueue: 底层是数组,有界
- LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值
由Blockqueue的继承机制可以看出其实他们就是一个单列集合,所以集合中的方法他们是可以使用的:
- 在创建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 }
下面写一个案例有助于理解:
-
案例需求
1.构造方法中接收一个阻塞队列对象
2.在run方法中循环向阻塞队列中添加包子
1.构造方法中接收一个阻塞队列对象
2.在run方法中循环获取阻塞队列中的包子
1.创建阻塞队列对象
2.创建生产者线程和消费者线程对象,构造方法中传入阻塞队列对象
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可能就会执行另一个线程,导致重复,但是实际上是做一个吃一个,做一个吃一个
迎风少年