线程高级应用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析
1.阻塞队列知识点
阻塞队列重要的有以下几个方法,具体用法可以参考帮助文档;区别说的很清楚,第一个种方法不阻塞直接抛异常;第二种方法是boolean型的,阻塞返回flase;第三种方法直接阻塞。
1 2. 案例分析 2 一: 3 package com.java5.thread.newSkill; 4 5 import java.util.concurrent.ArrayBlockingQueue; 6 import java.util.concurrent.BlockingQueue; 7 8 public class BlockingQueueTest { 9 10 /** 11 * 阻塞队列类:BlockingQueue 12 */ 13 public static void main(String[] args) { 14 15 final BlockingQueue queue = new ArrayBlockingQueue(3); 16 17 for(int i=0;i<2;i++){ 18 new Thread(){ 19 public void run() { 20 while(true){ 21 try{ 22 Thread.sleep((long)Math.random()*10000); 23 System.out.println(Thread.currentThread().getName()+" 准备放数据!"); 24 queue.put(1); 25 System.out.println(Thread.currentThread().getName()+" 已经放了数据,队列目前有: "+queue.size()+" 个数据!"); 26 }catch(Exception e){ 27 e.printStackTrace(); 28 } 29 } 30 } 31 }.start(); 32 } 33 34 new Thread(){ 35 public void run() { 36 while(true){ 37 try{ 38 //将此处睡眠时间分别改成100和1000,观察运行结果 39 /* 40 * 休息时间短,理论上应是:数据永远达不到三个,总是在第二个就被取走了; 41 * 但是本人操作总是有三个数据出现,不知道的原因所在, 42 * 感兴趣的大牛可以复制 代码测试一下; 43 * 休息时间长,数据总是三个,但是放的多取的少 44 */ 45 Thread.sleep(100); 46 System.out.println(Thread.currentThread().getName()+" 准备取数据!"); 47 queue.take(); 48 System.out.println(Thread.currentThread().getName()+" 已经取走数据,队列目前有: "+queue.size()+" 个数据!"); 49 }catch(Exception e){ 50 e.printStackTrace(); 51 } 52 } 53 } 54 }.start(); 55 } 56 57 } 58 59 二: 60 package com.java5.thread.newSkill; 61 62 import java.util.concurrent.ArrayBlockingQueue; 63 import java.util.concurrent.BlockingQueue; 64 65 /** 66 * 67 */ 68 public class BlockingQueueCommunication { 69 70 public static void main(String[] args) { 71 final Business business = new Business(); 72 new Thread(new Runnable() { 73 74 @Override 75 public void run() { 76 for (int i = 1; i <= 50; i++) { 77 business.sub(i); 78 } 79 } 80 }).start(); 81 82 for (int i = 1; i <= 50; i++) { 83 business.main(i); 84 } 85 86 } 87 88 /* 89 * 编写一个有子方法(用来调用子线程)和主方法(调用主线程)的业务类 加static是因为上面new的对象是final的,为了把这个类弄成外部类, 90 * 但是外部又有同名类,所以这样搞; 产生的类名为:BlockingQueueCommunication.Bussiness 91 */ 92 static class Business { 93 94 BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1); 95 BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1); 96 97 /* 98 * 这样直接在大括号内写的代码叫匿名构造方法;匿名构造方法优先与其他任何构造方法执行。 99 * 带上static关键字的叫做静态代码块,不带的也叫普通代码块 100 * 静态代码块在类加载的时候执行,只会执行一次;普通代码块创建几个对象就会执行几次。 101 */ 102 103 { 104 try { 105 System.out.println("我执行了,一上来就把queue2中放了一个数据"); 106 queue2.put(1); 107 } catch (InterruptedException e) { 108 e.printStackTrace(); 109 } 110 } 111 112 //此处要注意的问题:一定不要用同步锁sychronized,否则效果达不到还会出粗 113 //因为阻塞已经类似到了同步的功能,再用同步锁就是死锁了 114 public void sub(int i) { 115 try { 116 queue1.put(1); 117 } catch (InterruptedException e) { 118 e.printStackTrace(); 119 } 120 for (int j = 1; j <= 10; j++) { 121 System.out.println("sub thread sequence of " + j 122 + " ,loop of " + i); 123 } 124 try { 125 queue2.take(); 126 } catch (InterruptedException e) { 127 e.printStackTrace(); 128 } 129 } 130 131 public void main(int i) { 132 try { 133 queue2.put(1); 134 } catch (InterruptedException e) { 135 e.printStackTrace(); 136 } 137 for (int j = 1; j <= 100; j++) { 138 System.out.println("main thread sequence of " + j 139 + " ,loop of " + i); 140 } 141 try { 142 queue1.take(); 143 } catch (InterruptedException e) { 144 e.printStackTrace(); 145 } 146 } 147 } 148 }