线程高级施用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析
线程高级应用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析
1.阻塞队列知识点
阻塞队列重要的有以下几个方法,具体用法可以参考帮助文档;区别说的很清楚,第一个种方法不阻塞直接抛异常;第二种方法是boolean型的,阻塞返回flase;第三种方法直接阻塞。
2. 案例分析 一: package com.java5.thread.newSkill; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class BlockingQueueTest { /** * 阻塞队列类:BlockingQueue */ public static void main(String[] args) { final BlockingQueue queue = new ArrayBlockingQueue(3); for(int i=0;i<2;i++){ new Thread(){ public void run() { while(true){ try{ Thread.sleep((long)Math.random()*10000); System.out.println(Thread.currentThread().getName()+" 准备放数据!"); queue.put(1); System.out.println(Thread.currentThread().getName()+" 已经放了数据,队列目前有: "+queue.size()+" 个数据!"); }catch(Exception e){ e.printStackTrace(); } } } }.start(); } new Thread(){ public void run() { while(true){ try{ //将此处睡眠时间分别改成100和1000,观察运行结果 /* * 休息时间短,理论上应是:数据永远达不到三个,总是在第二个就被取走了; * 但是本人操作总是有三个数据出现,不知道的原因所在, * 感兴趣的大牛可以复制 代码测试一下; * 休息时间长,数据总是三个,但是放的多取的少 */ Thread.sleep(100); System.out.println(Thread.currentThread().getName()+" 准备取数据!"); queue.take(); System.out.println(Thread.currentThread().getName()+" 已经取走数据,队列目前有: "+queue.size()+" 个数据!"); }catch(Exception e){ e.printStackTrace(); } } } }.start(); } } 二: package com.java5.thread.newSkill; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; /** * */ public class BlockingQueueCommunication { public static void main(String[] args) { final Business business = new Business(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub(i); } } }).start(); for (int i = 1; i <= 50; i++) { business.main(i); } } /* * 编写一个有子方法(用来调用子线程)和主方法(调用主线程)的业务类 加static是因为上面new的对象是final的,为了把这个类弄成外部类, * 但是外部又有同名类,所以这样搞; 产生的类名为:BlockingQueueCommunication.Bussiness */ static class Business { BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1); BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1); /* * 这样直接在大括号内写的代码叫匿名构造方法;匿名构造方法优先与其他任何构造方法执行。 * 带上static关键字的叫做静态代码块,不带的也叫普通代码块 * 静态代码块在类加载的时候执行,只会执行一次;普通代码块创建几个对象就会执行几次。 */ { try { System.out.println("我执行了,一上来就把queue2中放了一个数据"); queue2.put(1); } catch (InterruptedException e) { e.printStackTrace(); } } //此处要注意的问题:一定不要用同步锁sychronized,否则效果达不到还会出粗 //因为阻塞已经类似到了同步的功能,再用同步锁就是死锁了 public void sub(int i) { try { queue1.put(1); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 1; j <= 10; j++) { System.out.println("sub thread sequence of " + j + " ,loop of " + i); } try { queue2.take(); } catch (InterruptedException e) { e.printStackTrace(); } } public void main(int i) { try { queue2.put(1); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 1; j <= 100; j++) { System.out.println("main thread sequence of " + j + " ,loop of " + i); } try { queue1.take(); } catch (InterruptedException e) { e.printStackTrace(); } } } }