JavaEE初阶(6)——自定义阻塞队列

本文旨在 讨论阻塞队列 以及自定义阻塞队列 及其相关原理

1.基本概念

阻塞队列是一种更复杂的队列——可以保证线程安全

阻塞特性

  • 队列为空时,尝试出队列,出队列操作会阻塞,阻塞到 其他线程添加元素为止
  • 队列为满时,尝试入队列,入队列操作会阻塞,阻塞到 其他线程拿走元素为止
  • 阻塞队列 一个最主要的应用场景,就是实现“生产者消费者模型”——一种特殊的编码技巧

例如:包饺子         擀饺子皮 的人属于 生产者        用饺子皮包饺子的人属于 消费者

        饺子皮属于资源  放饺子皮的菜板 属于生产消费的交易场所——此处的交易场所就是阻塞队列

阻塞——是极端情况生产者,消费者之间速度不协调的情况

1.1生产者 消费者模型优势

1.解耦合(不一定是两个线程之间 也可以是两个服务器)

如果A B之间直接访问,那么AB的耦合就更高 

通过使用阻塞队列 作为中间载体 可以降低耦合,降低后续修改成本

2.削峰填谷

如果出现上游服务器A 流量激增,为了控制节奏,先放入阻塞队列,高峰期 B服务器慢慢处理队列中的请求,低谷期时 可以赶紧处理剩余的请求。

1.2生产者消费者模型付出的代价

  1. 引入队列之后,整体结构会更加复杂,此时需要更多硬件资源,进行部署,生产环境的结构会更加复杂,难以管理。
  2. 效率会被影响

2.Java中ArrayList 和 LinkedList 有什么区别【经典面试题】

和顺序表 链表不同

顺序表:尾插尾删 O(1)        头插头删除 或 中间插入删除 O(N)

链表:任意位置插入删除 O(1)

但是在LinkedList类中 由于接口封装失误 无法发挥链表全部能力

LinkedList 执行add(插入的值,插入下标)

——寻找插入下标 需要从头找到指定下标位置,才能插入O(N)    中间位置删除,同理 

3.使用循环队列实现阻塞队列

class MyBlockQueue{
    private String[] date=null;
    //队首
    private int head=0;
    //队尾
    private int tail=0;
    //队列元素个数
    private int size=0;
    public MyBlockQueue(int capcity){
        date=new String[capcity];
    }
    public void put(String elem) throws InterruptedException {
        synchronized (this) {
            while (size>= date.length){
                //队列满 需要进行阻塞
                this.wait();
            }
            date[tail]=elem;
            tail++;
            if(tail>= date.length){
                tail=0;
            }
            size++;
            this.notify();
        }
    }
    public String take() throws InterruptedException {
        synchronized (this) {
            while (size==0){
                //队列空 需要进行阻塞
    //            return null;
                this.wait();
            }
            String ret =date[head];
            head++;
            if(head>= date.length){
                head=0;
            }
            size--;
            this.notify();
            return ret;
        }
    }
}

Put 中 this.wait()  当队列不满时 才进行唤醒——即其他线程成功执行take        

take中 this.wait()  当队列不空时 才进行唤醒——即其他线程成功执行put

put 与 take 的等待 唤醒 是相对的

由图知 当t1.put 成功执行后 此刻队列非空 其他线程可以执行put  因此唤醒 take同理 

为什么要使用while 判断size是否为零 而不是IF呢

由于wait 不仅仅会被notify 唤醒 还有可能因为Interrupt这样的方法中断

所以使用if作为wait的判断条件——存在wait被提前唤醒的风险 

并且使用while 目的是二次验证  再次确认队列空不空

在官方文档中,wait设计时 就是搭配while使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值