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
分享到:
相关推荐
此外,JDK 1.5还引入了新的编译器——Client Compiler和Server Compiler,根据不同的场景选择合适的编译策略,提升代码执行速度。 总结,JDK 1.5的64位Windows版本为Java开发者提供了在64位系统上开发和运行Java...
Java Development Kit(JDK)是Java编程语言的核心组件,它为开发者提供了编译、调试和运行Java应用程序所需的所有工具。JDK1.5是Java的一个重要版本,它在2004年9月30日正式发布,也被称为Java 5.0。这个版本引入了...
Linux系统中的JDK1.5是Java开发工具包的一个早期版本,主要针对Java语言的编译、运行和调试提供支持。这个版本在今天已经相对较为罕见,因为Java已经有了多个后续版本,包括JDK7、JDK8、JDK9直至最新的JDK17等。然而...
Java JDK(Java Development Kit)是Java编程语言的开发环境,它是Oracle公司提供的用于编写、调试和运行Java应用程序的工具集合。JDK1.5,也称为Java 5.0,是一个重要的版本,它引入了许多新的特性和改进,对Java...
这个压缩包包含了三个不同版本的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最重要的特性之一,它允许在类、接口和方法声明中使用类型参数,以实现数据类型的参数化。泛型提高了代码的类型安全性和可读性,减少了类型转换的需要,并允许编译器检查类型错误。 2. **自动装箱与...
jdk1.5.exe jdk1.5 jdk1.5下载
绝版jdk1.5,非常不错的资源。用起来很好。是 Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新 的值。通过getName/setName来访问name属性,...
总结来说,JDK1.5 32位绿色免安装版为Windows用户提供了便捷的Java开发和运行环境,特别是对于需要在多个JDK版本之间切换的开发者,这是一个高效的选择。同时,理解每个组件的作用以及如何设置和管理多个JDK版本,是...
本压缩包包含了JDK的两个重要版本:1.5(也称为Java 5)和1.6(Java 6),这两个版本在历史上对Java社区有着深远的影响。 JDK 1.5(2004年发布)是Java发展的一个重要里程碑,引入了许多新特性,极大地提升了开发...
前几天上传过这个资源,因为是在jdk1.6上开发的, 测试了一下在jdk1.5上不能用, 今天重新用jdk1.5编译了一下, 这个是可以支持jdk1.5+的 将 pu-xlscommon-1.0.0.jar 添加到工程的 /lib 目录下 用法在附件中 XlsTest....
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...
8. **NIO.2(New I/O 2)**:虽然NIO(非阻塞I/O)是在JDK1.4引入的,但JDK1.5对其进行了扩展,添加了文件系统操作和文件观察者等功能,使得文件操作更加高效和灵活。 9. **类型安全的异常检查(Checked Exceptions...
10. **NIO.2(New IO 2.0)**:虽然不是JDK1.5的一部分,但在后续的Java版本中,NIO(非阻塞I/O)进行了大量增强,增加了文件通道、文件属性和异步I/O等功能。 11. **异常链(Exception Chaining)**:当一个异常在...
Java Development Kit(JDK)是Java编程语言的核心组件,它为开发者提供了编译、调试和运行Java应用程序所需的所有工具。JDK1.5,也被称为JDK 5.0,是一个重要的版本,它引入了许多创新特性,显著提升了开发效率和...
IBM JDK 1.5 for Linux 64位是一款专为Linux操作系统设计的Java开发工具包,由IBM公司提供。此版本的JDK是基于Java Development Kit(JDK)1.5,也称为Java 5.0,它在Java平台标准版(Java SE)的历史上是一个重要的...
1. 泛型(Generics): JDK 1.5引入了泛型,允许在类、接口和方法中定义类型参数,增强了代码的类型安全性,减少了类型转换的麻烦。泛型使得在编译时就能检测到可能的类型错误,而不是在运行时抛出异常。 2. 自动...
测试可用的linux版jdk1.5,jdk-1_5_0_19-linux-i586-rpm.bin
在Linux环境下,Java Development Kit(JDK)1.5是Java编程语言的重要组成部分,它提供了必要的工具和库,使得开发者能够在Linux系统上进行Java应用程序的开发、编译、调试以及运行。本文将深入探讨Linux下JDK1.5的...
另外,JDK1.5还对I/O流进行了改进,引入了NIO(非阻塞I/O)框架,提供了通道(Channels)和缓冲区(Buffers)的概念,提高了读写操作的效率,尤其适用于高并发的网络应用。 总的来说,JDK1.5对Java语言做了大量的...