BlockingQueue介绍及使用
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
|
|
抛出异常 | 特殊值 | 阻塞 | 超时 |
| 插入 | add(e) |
offer(e) |
put(e) |
offer(e, time, unit) |
| 移除 | remove() |
poll() |
take() |
poll(time, unit) |
| 检查 | element() |
peek() |
不可用 | 不可用 |
3.BlockingQueue定义的常用方法详解:
1)add(anObject):把anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则报异常
2)offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.
3)put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.
4)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null
5)take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止
2.BlockingQueue有四个具体的实现类,根据不同需求,选择不同的实现类
1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的.
2)LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的 BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含 的对象是以FIFO(先入先出)顺序排序的
3)PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序.
4)SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的.
3.LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致 LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于 ArrayBlockingQueue.
在网上找到两个例子 :
1 package com.thread; 2 import java.util.concurrent.ArrayBlockingQueue; 3 import java.util.concurrent.BlockingQueue; 4 5 public class BlockingQueueTest { 6 public static void main(String[] args) { 7 final BlockingQueue queue = new ArrayBlockingQueue(3); 8 for(int i=0;i<2;i++){ 9 new Thread(){ 10 public void run(){ 11 while(true){ 12 try { 13 Thread.sleep((long)(Math.random()*1000)); 14 System.out.println(Thread.currentThread().getName() + "准备放数据!"); 15 queue.put(1); 16 System.out.println(Thread.currentThread().getName() + "已经放了数据," + 17 "队列目前有" + queue.size() + "个数据"); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 22 } 23 } 24 25 }.start(); 26 } 27 28 new Thread(){ 29 public void run(){ 30 while(true){ 31 try { 32 //将此处的睡眠时间分别改为100和1000,观察运行结果 33 Thread.sleep(1000); 34 System.out.println(Thread.currentThread().getName() + "准备取数据!"); 35 queue.take(); 36 System.out.println(Thread.currentThread().getName() + "已经取走数据," + 37 "队列目前有" + queue.size() + "个数据"); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 } 42 } 43 44 }.start(); 45 } 46 }
***********************************
1 public class BlockingQueueCondition { 2 3 public static void main(String[] args) { 4 ExecutorService service = Executors.newSingleThreadExecutor(); 5 final Business3 business = new Business3(); 6 service.execute(new Runnable(){ 7 8 public void run() { 9 for(int i=0;i<50;i++){ 10 business.sub(); 11 } 12 } 13 14 }); 15 16 for(int i=0;i<50;i++){ 17 business.main(); 18 } 19 } 20 21 } 22 23 class Business3{ 24 BlockingQueue subQueue = new ArrayBlockingQueue(1); 25 BlockingQueue mainQueue = new ArrayBlockingQueue(1); 26 //这里是匿名构造方法,只要new一个对象都会调用这个匿名构造方法,它与静态块不同,静态块只会执行一次, 27 //在类第一次加载到JVM的时候执行 28 //这里主要是让main线程首先put一个,就有东西可以取,如果不加这个匿名构造方法put一个的话程序就死锁了 29 { 30 try { 31 mainQueue.put(1); 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 } 36 public void sub(){ 37 try 38 { 39 mainQueue.take(); 40 for(int i=0;i<10;i++){ 41 System.out.println(Thread.currentThread().getName() + " : " + i); 42 } 43 subQueue.put(1); 44 }catch(Exception e){ 45 46 } 47 } 48 49 public void main(){ 50 51 try 52 { 53 subQueue.take(); 54 for(int i=0;i<5;i++){ 55 System.out.println(Thread.currentThread().getName() + " : " + i); 56 } 57 mainQueue.put(1); 58 }catch(Exception e){ 59 } 60 } 61 }

浙公网安备 33010602011771号