线程高级施用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析

线程高级应用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析

1.阻塞队列知识点

线程高级施用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析

线程高级施用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析

   阻塞队列重要的有以下几个方法,具体用法可以参考帮助文档;区别说的很清楚,第一个种方法不阻塞直接抛异常;第二种方法是boolean型的,阻塞返回flase;第三种方法直接阻塞。

线程高级施用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析

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();
			}
		}
	}
}