`

jdk1.5——可阻塞队列(自定义和jdk提供类的两种实现写法)

 
阅读更多
 

 1 查看api 搜索关键词: BlockingQueue

  可以看到具体实现类:

所有已知实现类:
ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue

2 概念理解: 一个队列(理解成数组),一个人不停的放面包,一个人不停的取面包,当放满时,放队列阻塞,放面包的人等待;  当取面包到没有时,取动作阻塞,取面包的人等待;

 

 

3 使用jdk提供实现类,模拟阻塞效果:

 

 

package cn.itcast.heima2;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 *   其内部代码 和自定义写法一样  也是弄出两个队列来
 *    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = (E[]) new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
 * @author zm
 * 
 * 测试结果:
 * Thread-0准备放数据!
Thread-0已经放了数据,队列目前有1个数据
Thread-1准备放数据!
Thread-1已经放了数据,队列目前有2个数据
Thread-2准备取数据!
Thread-2已经取走数据,数据为: 1 队列目前有1个数据
Thread-1准备放数据!
Thread-1已经放了数据,队列目前有2个数据
Thread-0准备放数据!
Thread-0已经放了数据,队列目前有3个数据
Thread-1准备放数据!    ------------------------> 此时篮子满了, 放队列进入阻塞
Thread-0准备放数据!
Thread-2准备取数据!
Thread-2已经取走数据,数据为: 1 队列目前有2个数据 -----------------------> 此时取走了一个面包 篮子不满
Thread-1已经放了数据,队列目前有3个数据  -----------------------> 此时才能继续放面包
 *
 */
public class BlockingQueueTest {
	public static void main(String[] args) {
		final BlockingQueue queue = new ArrayBlockingQueue(3);   // 定义篮子为3个大小
		for(int i=0;i<2;i++){ // 两个人,不停向篮子 放面包
			new Thread(){
				public void run(){
					while(true){
						try {
							Thread.sleep((long)(Math.random()*1000));
							System.out.println(Thread.currentThread().getName() + "准备放数据!");							
							queue.put(1);
							System.out.println(Thread.currentThread().getName() + "已经放了数据," + 							
										"队列目前有" + queue.size() + "个数据");
						} catch (InterruptedException e) {
							e.printStackTrace();
						}

					}
				}
				
			}.start();
		}
		
		new Thread(){
			public void run(){ // 一个人 不停的从篮子中 取面包
				while(true){ 
					try {
						//将此处的睡眠时间分别改为100和1000,观察运行结果
						Thread.sleep(1000); // 
						System.out.println(Thread.currentThread().getName() + "准备取数据!");
						Object object = queue.take();
						
						System.out.println(Thread.currentThread().getName() + "已经取走数据,数据为: " + object +							
								" 队列目前有" + queue.size() + "个数据");					
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		}.start();			
	}
}

 

 
4 使用自定义阻塞队列方式,实现 存取篮子面包效果:
 
package thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @author zm
 
 *  结果:
向第0个篮子生产了一个面包,面包重量为 25g
从第0个篮子拿走了一个面包,面包重量为 25g
向第1个篮子生产了一个面包,面包重量为 73g
向第2个篮子生产了一个面包,面包重量为 40g
从第1个篮子拿走了一个面包,面包重量为 73g
向第3个篮子生产了一个面包,面包重量为 50g
向第4个篮子生产了一个面包,面包重量为 90g
从第2个篮子拿走了一个面包,面包重量为 40g
从第3个篮子拿走了一个面包,面包重量为 50g
向第5个篮子生产了一个面包,面包重量为 50g
向第6个篮子生产了一个面包,面包重量为 77g
从第4个篮子拿走了一个面包,面包重量为 90g
 *  
 *  
 *  案例2: 两队人,一对不停像100个篮子生产面包,一对不停从篮子拿走面包(阻塞队列)
 *  
 *  如果是我不停的生产面包放在篮子里,我不管消费者拿面包, notfull队列(篮子还没存放满面包队列 有自己独自的wait nodify)
 *  而消费者不停的去从篮子里拿面包,而不管生产者生产了多少,  notempty队列(篮子面包还没空队列 有自己独自的wait nodify)
 *  那么这就是两个队列,
 *  notfull队列, 只管像篮子里放面包,当100个篮子满的时,放面包动作处于等待
 *  notempty队列,只管从篮子里拿面包,当100个篮子空的时,存面包动作处于等待
 *  此时需要使用同一个lock的两个condition来实现第二个案例
 *  
 *  
 *  注意: count表示当前面包真实个数(生产一个 同时下个线程拿走一个 那么count = 0)
 *  items: 存放面包篮子
 *  putptr, 生产面包后 存放在篮子的角标,
 *  takeptr,取走面包时,面包所在篮子的角标
 * 
 */
public class CommunicateWithConditionThread {

	public static void main(String[] args) {
		
		final BoundedBuffer boundedBuffer = new BoundedBuffer();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep((long)(Math.random()*100));
						boundedBuffer.put((int)(Math.random()*100));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
			}
		}).start();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep((long)(Math.random()*100));
						boundedBuffer.take();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
		
		
		
	}

}




class BoundedBuffer {
	   final Lock lock = new ReentrantLock();
	   final Condition notFull  = lock.newCondition(); // 生产队列
	   final Condition notEmpty = lock.newCondition(); // 消费队列

	   final Object[] items = new Object[20];
	   int putptr, takeptr, count;

	   public void put(int x) throws InterruptedException {
	     lock.lock(); // 生产面包上锁
	     try {
	       while (count == items.length)  // 当生产队列并发大到突然生产了100个面包时,生产队列等待
	         notFull.await();
			 // 否则执行生产面包操作, 不断向数组下一个单元格内放新面包
	       items[putptr] = x; 
	       System.out.println("向第" + putptr + "个篮子生产了一个面包,面包重量为 " + x + "g" );
	       if (++putptr == items.length) putptr = 0;// 当存放的面包到达数组最后位置时,篮子存放面包位置又从0开始
	       ++count; // 记录面包个数
	       
	       notEmpty.signal();// 生产了面包,就立即通知消费队列去取走面包
	     } finally {
	       lock.unlock();// 生产面包完成 解锁 让下个生产执行
	     }
	   }

	   public Object take() throws InterruptedException {
	     lock.lock();// 取面包上锁
	     try {
	       while (count == 0) // 当消费队列消费并发过大,或者刚开始没生产出面包时,消费队列等待
	         notEmpty.await();
	       Object x = items[takeptr]; 
	       System.out.println("从第" + takeptr + "个篮子拿走了一个面包,面包重量为 " + x + "g" );
	       if (++takeptr == items.length) takeptr = 0;// 当取走面包到篮子最后一个位置时,重置,再从篮子最开始位置取面包
	       --count;// 记录面包个数 取走一次面包 个数减一
	       notFull.signal(); // 取走面包, 立即通知生产队列生产面包
	       return x;
	     } finally {
	       lock.unlock(); // 取面包完成 解锁 让下个取面包动作执行 
	     }
	  
 
 5 使用阻塞队列方式,实现 打印日志提高效率:
 
// 原来写法,耗时16S
public class Thread16 {

	/**
	 * 打印16个日志  耗时16S	
	 */
	public static void main(String[] args) {

		System.out.println("begin: " + (System.currentTimeMillis()/1000));
		for(int i=0; i<16; i++){ // 不能改
			String log = "" + (i + 1);// 不能改   
			parseLog(log);
		}
	}
	
	public static void parseLog(String log){
		
		System.out.println("log: " + (System.currentTimeMillis()/1000));
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}

}


修改程序代码,开四个线程让这16个对象在4秒钟打完
思路: 
	0创建容量16的队列
	1 将16个任务增加到 阻塞队列中	
	2开启4个线程,每次从队列中获取数据
	
	这样主线程不停的放, 并发来的4个线程不停的取, 你可以理解为并发一次来了4个线程,每个线程取到后内部打印1S操作仍旧不变,
	执行4次,一共耗时4S完成原来16秒不用并发下的操作
	
	主线程放log 和 子线程取log 之间用condtion notEmpty notFull 来实现阻塞


public class Test {
	
	public static void main(String[] args){
		// 0 创建容量只为1的队列
        final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);
        // 2 开启4个线程,每次从队列中获取数据
		for(int i=0;i<4;i++){
			new Thread(new Runnable(){
				@Override
				public void run() {
					while(true){
						try {
							String log = queue.take();
							parseLog(log);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				
			}).start();
		}
		
		// 1 将16个任务在主线程中增加到阻塞队列中
		System.out.println("begin:"+(System.currentTimeMillis()/1000));
		for(int i=0;i<16;i++){  //这行代码不能改动
			final String log = ""+(i+1);//这行代码不能改动
			{
					try {
						queue.put(log);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	     			//Test.parseLog(log);
			}
		}
	}
	
	//parseLog方法内部的代码不能改动
	public static void parseLog(String log){
		System.out.println(log+":"+(System.currentTimeMillis()/1000));
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}
	
}
 
 
脑图:


 
 
  • 大小: 11.8 KB
分享到:
评论

相关推荐

    jdk1.5 windows版本 64位

    此外,JDK 1.5还引入了新的编译器——Client Compiler和Server Compiler,根据不同的场景选择合适的编译策略,提升代码执行速度。 总结,JDK 1.5的64位Windows版本为Java开发者提供了在64位系统上开发和运行Java...

    jdk1.5x64位 windows版.zip

    Java Development Kit(JDK)是Java编程语言的核心组件,它为开发者提供了编译、调试和运行Java应用程序所需的所有工具。JDK1.5是Java的一个重要版本,它在2004年9月30日正式发布,也被称为Java 5.0。这个版本引入了...

    linux系统jdk1.5下载

    Linux系统中的JDK1.5是Java开发工具包的一个早期版本,主要针对Java语言的编译、运行和调试提供支持。这个版本在今天已经相对较为罕见,因为Java已经有了多个后续版本,包括JDK7、JDK8、JDK9直至最新的JDK17等。然而...

    Java-jdk1.5安装包

    Java JDK(Java Development Kit)是Java编程语言的开发环境,它是Oracle公司提供的用于编写、调试和运行Java应用程序的工具集合。JDK1.5,也称为Java 5.0,是一个重要的版本,它引入了许多新的特性和改进,对Java...

    包含 jdk1.5免安装、jdk1.6免安装、jdk1.8(32和64)

    这个压缩包包含了三个不同版本的JDK:JDK 1.5、JDK 1.6和JDK 1.8,其中1.5和1.6是早期版本,而1.8是最流行且广泛使用的版本之一。 **JDK 1.5(也称为Java 5.0)** JDK 1.5在2004年发布,引入了许多重要的新特性,如...

    JDK1.5,JDK1.5

    泛型是JDK1.5最重要的特性之一,它允许在类、接口和方法声明中使用类型参数,以实现数据类型的参数化。泛型提高了代码的类型安全性和可读性,减少了类型转换的需要,并允许编译器检查类型错误。 2. **自动装箱与...

    jdk1.5.exe jdk1.5

    jdk1.5.exe jdk1.5 jdk1.5下载

    jdk1.5免安装版

    绝版jdk1.5,非常不错的资源。用起来很好。是 Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新 的值。通过getName/setName来访问name属性,...

    window JDK1.5 32位 绿色免安装版,可以安装多个JDK使用

    总结来说,JDK1.5 32位绿色免安装版为Windows用户提供了便捷的Java开发和运行环境,特别是对于需要在多个JDK版本之间切换的开发者,这是一个高效的选择。同时,理解每个组件的作用以及如何设置和管理多个JDK版本,是...

    jdk1.5、1.6压缩包

    本压缩包包含了JDK的两个重要版本:1.5(也称为Java 5)和1.6(Java 6),这两个版本在历史上对Java社区有着深远的影响。 JDK 1.5(2004年发布)是Java发展的一个重要里程碑,引入了许多新特性,极大地提升了开发...

    简单易用通用(xls,xlsx)导入导出操作 jdk1.5+

    前几天上传过这个资源,因为是在jdk1.6上开发的, 测试了一下在jdk1.5上不能用, 今天重新用jdk1.5编译了一下, 这个是可以支持jdk1.5+的 将 pu-xlscommon-1.0.0.jar 添加到工程的 /lib 目录下 用法在附件中 XlsTest....

    JDK1.5最终版全平台下载

    JDK1.5 全平台安装包下载 百度网盘资源 jdk-1_5_0_22-linux-amd64-rpm.bin jdk-1_5_0_22-linux-amd64.bin jdk-1_5_0_22-linux-i586-rpm.bin jdk-1_5_0_22-linux-i586.bin jdk-1_5_0_22-solaris-amd64...

    详细介绍JDK1.5的各种新特性

    8. **NIO.2(New I/O 2)**:虽然NIO(非阻塞I/O)是在JDK1.4引入的,但JDK1.5对其进行了扩展,添加了文件系统操作和文件观察者等功能,使得文件操作更加高效和灵活。 9. **类型安全的异常检查(Checked Exceptions...

    jdk jdk1.5 windows系统

    10. **NIO.2(New IO 2.0)**:虽然不是JDK1.5的一部分,但在后续的Java版本中,NIO(非阻塞I/O)进行了大量增强,增加了文件通道、文件属性和异步I/O等功能。 11. **异常链(Exception Chaining)**:当一个异常在...

    JDK1.5、JDK5下载

    Java Development Kit(JDK)是Java编程语言的核心组件,它为开发者提供了编译、调试和运行Java应用程序所需的所有工具。JDK1.5,也被称为JDK 5.0,是一个重要的版本,它引入了许多创新特性,显著提升了开发效率和...

    IBMJDK1.5linux.zip

    IBM JDK 1.5 for Linux 64位是一款专为Linux操作系统设计的Java开发工具包,由IBM公司提供。此版本的JDK是基于Java Development Kit(JDK)1.5,也称为Java 5.0,它在Java平台标准版(Java SE)的历史上是一个重要的...

    历史版本JDK1.5安装包

    1. 泛型(Generics): JDK 1.5引入了泛型,允许在类、接口和方法中定义类型参数,增强了代码的类型安全性,减少了类型转换的麻烦。泛型使得在编译时就能检测到可能的类型错误,而不是在运行时抛出异常。 2. 自动...

    jdk 1.5 linux (共三个文件)之一

    测试可用的linux版jdk1.5,jdk-1_5_0_19-linux-i586-rpm.bin

    linux下JDK1.5

    在Linux环境下,Java Development Kit(JDK)1.5是Java编程语言的重要组成部分,它提供了必要的工具和库,使得开发者能够在Linux系统上进行Java应用程序的开发、编译、调试以及运行。本文将深入探讨Linux下JDK1.5的...

    jdk1.5 windows 64位官方正式版,绝对有效

    另外,JDK1.5还对I/O流进行了改进,引入了NIO(非阻塞I/O)框架,提供了通道(Channels)和缓冲区(Buffers)的概念,提高了读写操作的效率,尤其适用于高并发的网络应用。 总的来说,JDK1.5对Java语言做了大量的...

Global site tag (gtag.js) - Google Analytics