(原创)JAVA阻塞队列LinkedBlockingQueue 以及非阻塞队列ConcurrentLinkedQueue 的区别
2015-11-26 16:10
686 查看
阻塞队列:线程安全
按FIFO(先进先出)排序元素。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
注意:
1、必须要使用take()方法在获取的时候达成阻塞结果
2、使用poll()方法将产生非阻塞效果
非阻塞队列
基于链接节点的、无界的、线程安全。此队列按照FIFO(先进先出)原则对元素进行排序。队列的头部是队列中时间最长的元素。队列的尾部是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共collection时,ConcurrentLinkedQueue是一个恰当的选择。此队列不允许null元素。
例子
在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。
使用非阻塞队列,虽然能即时返回结果(消费结果),但必须自行编码解决返回为空的情况处理(以及消费重试等问题)。
另外他们都是线程安全的,不用考虑线程同步问题。
按FIFO(先进先出)排序元素。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
注意:
1、必须要使用take()方法在获取的时候达成阻塞结果
2、使用poll()方法将产生非阻塞效果
importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; importjava.util.concurrent.LinkedBlockingDeque; importjava.util.concurrent.LinkedBlockingQueue; importjava.util.concurrent.TimeUnit; publicclassBlockingDeque{ //阻塞队列,FIFO privatestaticLinkedBlockingQueue<Integer>concurrentLinkedQueue=newLinkedBlockingQueue<Integer>(); publicstaticvoidmain(String[]args){ ExecutorServiceexecutorService=Executors.newFixedThreadPool(2); executorService.submit(newProducer("producer1")); executorService.submit(newProducer("producer2")); executorService.submit(newProducer("producer3")); executorService.submit(newConsumer("consumer1")); executorService.submit(newConsumer("consumer2")); executorService.submit(newConsumer("consumer3")); } staticclassProducerimplementsRunnable{ privateStringname; publicProducer(Stringname){ this.name=name; } publicvoidrun(){ for(inti=1;i<10;++i){ System.out.println(name+"生产:"+i); //concurrentLinkedQueue.add(i); try{ concurrentLinkedQueue.put(i); Thread.sleep(200);//模拟慢速的生产,产生阻塞的效果 }catch(InterruptedExceptione1){ //TODOAuto-generatedcatchblock e1.printStackTrace(); } } } } staticclassConsumerimplementsRunnable{ privateStringname; publicConsumer(Stringname){ this.name=name; } publicvoidrun(){ for(inti=1;i<10;++i){ try{ //必须要使用take()方法在获取的时候阻塞 System.out.println(name+"消费:"+concurrentLinkedQueue.take()); //使用poll()方法将产生非阻塞效果 //System.out.println(name+"消费:"+concurrentLinkedQueue.poll()); //还有一个超时的用法,队列空时,指定阻塞时间后返回,不会一直阻塞 //但有一个疑问,既然可以不阻塞,为啥还叫阻塞队列? //System.out.println(name+"Consumer"+concurrentLinkedQueue.poll(300,TimeUnit.MILLISECONDS)); }catch(Exceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } } }
非阻塞队列
基于链接节点的、无界的、线程安全。此队列按照FIFO(先进先出)原则对元素进行排序。队列的头部是队列中时间最长的元素。队列的尾部是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共collection时,ConcurrentLinkedQueue是一个恰当的选择。此队列不允许null元素。
例子
importjava.util.concurrent.ConcurrentLinkedQueue;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.LinkedBlockingDeque;
importjava.util.concurrent.TimeUnit;
publicclassNoBlockQueue{
privatestaticConcurrentLinkedQueue<Integer>concurrentLinkedQueue=newConcurrentLinkedQueue<Integer>();
publicstaticvoidmain(String[]args){
ExecutorServiceexecutorService=Executors.newFixedThreadPool(2);
executorService.submit(newProducer("producer1"));
executorService.submit(newProducer("producer2"));
executorService.submit(newProducer("producer3"));
executorService.submit(newConsumer("consumer1"));
executorService.submit(newConsumer("consumer2"));
executorService.submit(newConsumer("consumer3"));
}
staticclassProducerimplementsRunnable{
privateStringname;
publicProducer(Stringname){
this.name=name;
}
publicvoidrun(){
for(inti=1;i<10;++i){
System.out.println(name+"startproducer"+i);
concurrentLinkedQueue.add(i);
try{
Thread.sleep(20);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
//System.out.println(name+"endproducer"+i);
}
}
}
staticclassConsumerimplementsRunnable{
privateStringname;
publicConsumer(Stringname){
this.name=name;
}
publicvoidrun(){
for(inti=1;i<10;++i){
try{
System.out.println(name+"Consumer"+concurrentLinkedQueue.poll());
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
//System.out.println();
//System.out.println(name+"endConsumer"+i);
}
}
}
}
在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。
使用非阻塞队列,虽然能即时返回结果(消费结果),但必须自行编码解决返回为空的情况处理(以及消费重试等问题)。
另外他们都是线程安全的,不用考虑线程同步问题。
相关文章推荐
- ABAP 复制标准的GUI STATUS
- poj 1302 Blue Gene, Jr. 递归
- 标签控制器 UITabBarController
- leetcode-51 N-Queens N皇后问题
- Gorgeous Sequence
- UICollectionView的使用
- UIView常见属性(一)
- 使用CruiseControl.Net全面实现持续集成
- UI_搜索框UISearchController的使用(iOS8.0以后替代UISearchBar + UISearchDisplayController)
- Xcode调试UI
- EasyUI常见几种控件动态渲染的示范代码
- easyui-tooltip 提示框
- UI_UISearchController实现搜索功能
- iOS Human Interface Guidelines资源收藏
- PHP在foreach中对$value赋值无效的问题
- Extjs4.2 combobox setValue设置值
- PredicateBuilder 对 ADO.Net Entity Framework 支持的改进
- Machine Learning week 7 quiz: Support Vector Machines
- iso中输入框被软键盘覆盖的解决方案
- android UI学习书籍