黑马程序员——Java集合框架—Queue—BlockingQueue—ArrayBlockingQueue
来源:互联网 发布:java nextline 编辑:程序博客网 时间:2024/04/29 12:24
参考:
博客园:Java多线程-工具篇-BlockingQueue
红黑联盟:Java 7之多线程并发容器 - ArrayBlockingQueue(源码分析)
CSDN:余志强 Java5 多线程(八)-- ArrayBlockingQueue阻塞队列
ArrayBlockingQueue
引用参考文章中的一段话:
“基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。
ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于LinkedBlockingQueue;按照实现原理来分析,ArrayBlockingQueue完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。Doug Lea之所以没这样去做,也许是因为ArrayBlockingQueue的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜。 ArrayBlockingQueue和LinkedBlockingQueue间还有一个明显的不同之处在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,而后者则会生成一个额外的Node对象。这在长时间内需要高效并发地处理大批量数据的系统中,其对于GC的影响还是存在一定的区别。而在创建ArrayBlockingQueue时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。”
ArrayBlockingQueue队列的长度是固定的,一旦被创建,将无法改变队列的大小;队列的大小是通过构造函数指定的。
从ArrayBlockingQueue的构造方法可以看出,在创建其对象时,必须要指定队列的长度。
ArrayBlockingQueue实现了Collection中所有的方法,也就是说可以在ArrayBlockingQueue中调用它从Collection中继承的方法。同样可以使用Iterator来迭代ArrayBlockingQueue中的元素。
小示例:
package org.lgy.study.collection;import java.util.concurrent.BlockingQueue;import java.util.concurrent.ArrayBlockingQueue;/* javac -d classes "src/org/lgy/study/collection/ArrayBlockingQueueTest.java"java org.lgy.study.collection.ArrayBlockingQueueTest */public class ArrayBlockingQueueTest{public static void main(String[] args){// 阻塞队列,容量为1BlockingQueue<Object> bq = new ArrayBlockingQueue<>(1);// 创建3个生产者线程for(int i = 0; i < 3; i++){new Thread(new Producer(bq), "生产者-" + i).start();}// 创建1个消费者线程new Thread(new Consumer(bq), "消费者-" + 1).start();}// 生产者线程private static class Producer implements Runnable{private BlockingQueue<Object> bq;private Object obj;public Producer(BlockingQueue<Object> bq){this.bq = bq;}public void run(){// 每一个生产者线程都仅仅生产10个数据for(int i = 0; i < 10; i++){try{obj = new Object();// System.out.println(Thread.currentThread().getName() + ",即将放入数据... ...");bq.put(obj); // 如果队列已满,则阻塞当前线程(即当前线程会停止在这里,不再继续往下执行)System.out.println(Thread.currentThread().getName() + obj);Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}}}}// 消费者线程private static class Consumer implements Runnable{private BlockingQueue<Object> bq;private Consumer(BlockingQueue<Object> bq){this.bq = bq;}public void run(){try{while(true){// 如果队列为空,则take方法会阻塞当前线程System.out.println(Thread.currentThread().getName() + bq.take());Thread.sleep(100);}}catch(InterruptedException e){e.printStackTrace();}}}}/* 结果:生产者-1java.lang.Object@70e25c99消费者-1java.lang.Object@70e25c99生产者-0java.lang.Object@5e70125b消费者-1java.lang.Object@5e70125b生产者-2java.lang.Object@3b68c294消费者-1java.lang.Object@3b68c294生产者-1java.lang.Object@7e25bcf5消费者-1java.lang.Object@7e25bcf5生产者-0java.lang.Object@50b7f7e5消费者-1java.lang.Object@50b7f7e5生产者-2java.lang.Object@3f575121消费者-1java.lang.Object@3f575121生产者-1java.lang.Object@7a1a37e9消费者-1java.lang.Object@7a1a37e9生产者-0java.lang.Object@5488792b消费者-1java.lang.Object@5488792b生产者-2java.lang.Object@7a55c8af消费者-1java.lang.Object@7a55c8af生产者-1java.lang.Object@3f18b6ce消费者-1java.lang.Object@3f18b6ce生产者-0java.lang.Object@118afdde消费者-1java.lang.Object@118afdde... ... */
问题一:死锁
看如下2段回导致死锁的代码:
生产者中的run方法:
public void run(){// 每一个生产者线程都仅仅生产10个数据for(int i = 0; i < 10; i++){try{synchronized(bq){obj = new Object();// System.out.println(Thread.currentThread().getName() + ",即将放入数据... ...");bq.put(obj); // 如果队列已满,则阻塞当前线程(即当前线程会停止在这里,不再继续往下执行)System.out.println(Thread.currentThread().getName() + obj);}Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}}}
消费者中的run方法:
public void run(){try{while(true){synchronized(bq){// 如果队列为空,则take方法会阻塞当前线程System.out.println(Thread.currentThread().getName() + bq.take());}Thread.sleep(100);}}catch(InterruptedException e){e.printStackTrace();}}
这2段代码与上面代码的区别仅仅是添加了synchronized代码块,添加synchronized代码块的初衷是想把一部分代码封装成一个原子操作,最终却导致了死锁。
死锁的原因如下:
对于生产者,程序首先会获取bq的锁,然后执行synchronized代码块,如果此时队列已满,调用put方法时将导致当前线程阻塞,当前现场就会停止在put方法处不再往下执行,从而导致不能释放bq的锁。
由于队列已满,所以应该有消费者take数据,消费者也先试图获取bq的锁,但由于bq的锁一直被某个生产者拿着,所以导致消费者进程阻塞,无法取数据。
最终产生了死锁。
- 黑马程序员——Java集合框架—Queue—BlockingQueue—ArrayBlockingQueue
- 黑马程序员——Java集合框架—Queue—BlockingQueue—LinkedBlockingQueue
- 黑马程序员——Java集合框架—Queue—BlockingQueue—DelayQueue
- 黑马程序员——Java集合框架—Queue—BlockingQueue—SynchronousQueue
- 黑马程序员——Java集合框架—Queue—BlockingQueue
- 黑马程序员——Java集合框架—Queue接口
- 黑马程序员——Java集合框架—Queue—Deque—ArrayDeque
- 黑马程序员——Java集合框架—Queue—PriorityQueue
- 黑马程序员——Java集合框架—Queue—Deque
- 黑马程序员——Java集合框架
- 黑马程序员——Java集合框架
- 黑马程序员——java集合框架
- 黑马程序员——java-集合框架
- 黑马程序员——JAVA集合框架
- 黑马程序员——java集合框架
- 黑马程序员——Java集合框架
- 黑马程序员——Java集合框架
- 黑马程序员—java集合框架应用
- Current online Redo 和 Undo 损坏的处理方法
- 【BZOJ】1500 [NOI2005]维修数列 【splay】
- UVA 10006 - Carmichael Numbers (快速幂+筛素数)
- 3socket编程:UDP编程
- 【C++】STL容器的总结
- 黑马程序员——Java集合框架—Queue—BlockingQueue—ArrayBlockingQueue
- Stanford机器学习---第三讲. 逻辑回归和过拟合问题的解决 logistic Regression & Regularization
- 浅谈响应式布局
- 三款JSON类库Jackson,Gson与JSON-lib的性能对比
- ORACLE介质管理库MML
- 排序11:计数排序
- Stanford机器学习---第四讲. 神经网络的表示 Neural Networks representation
- Thread
- Cordova Xcode iOS入门教程