阻塞队列——生产者消费者模型

目录

阻塞队列

生产者消费者模型意义

java标准库中,已经提供了现成的阻塞队列

如何自己实现阻塞队列?

阻塞队列最终版本


阻塞队列

是特殊的队列

①线程安全

②带有阻塞特性

    a.如果队列为空,继续出队列,就会发生阻塞,阻塞到其他线程往队列里添加元素为止

    b.如果队列为满,继续入队列,也会发生阻塞,阻塞到其他线程从队列里取走元素为止

阻塞队列的最大意义,用来实现”生产者消费者“模型

生产者消费者模型意义

1.解耦合

比如,考虑一个简单的分布式系统

相比之下,使用生产者消费者模型就可以解决上述耦合问题

2.削峰填谷

(峰:请求量比较多 谷:请求量比较少)

引入生产者消费者模型后

java标准库中,已经提供了现成的阻塞队列

针对BlockingQueue提供了两种实现方式

1.基于数组

2.基于链表

public interface BlockingQueue<E> extends Queue<E>{}

put入阻塞队列

take出阻塞队列

如何自己实现阻塞队列?

一个普通队列+线程安全+阻塞

普通环形队列(这里采用设一个size记录长度的方式):

public void put(String elem){
        if(size==data.length){
            return;
        }
        data[tail]=elem;
        tail++;
        if(tail==data.length){
            tail=0;
        }
        size++;
    }

    public String take(){
        if(size==0){
            return null;
        }
        String ret=data[head];
        head++;
        if(head==data.length){
            head=0;
        }
        size--;
        return ret;
    }

实现阻塞队列:

 public void put(String elem) throws InterruptedException {
        if(size==data.length){
            //如果队列满 阻塞等待 直到有元素take
            this.wait();
            return;
        }
        data[tail]=elem;
        tail++;
        if(tail==data.length){
            tail=0;
        }
        size++;
        //put后 队列中有元素了 释放take中的wait(如果有的话)
        this.notify();
    }
    public String take() throws InterruptedException {
        if(size==0){
            //如果队列空 阻塞等待 直到有元素put
            this.wait();
            return null;
        }
        String ret=data[head];
        head++;
        if(head==data.length){
            head=0;
        }
        size--;
        //take后 队列中不满了,释放put中的wait(如果有的话)
        this.notify();
        return ret;
    }
if(size==data.length){
        try{
            this.wait();
        }catch(InterruptedException e){
            
        }
    }

如果代码这样写,出现异常后方法不会结束,会继续往下执行,会出现bug

public void put(String elem) throws InterruptedException

而采用这种方法,出现异常后,方法会结束,不会出现bug

所以,加一个判断条件,wait唤醒后再确认一次队列满不满,如果队列还是满的,继续wait)

后续的代码中,有的要进行读(判定),有的要进行写(修改),为了避免内存可见性问题,加上volatile

阻塞队列最终版本

public class BlockingQueue {
    private String[] data = new String[1000];
    private volatile int head = 0;
    // 队列的结束位置的下一个位置.
    private volatile int tail = 0;
    // 队列中有效元素的个数.
    private volatile int size = 0;
    public void put(String elem) throws InterruptedException {
        if(size==data.length){
            //如果队列满 阻塞等待 直到有元素take
            this.wait();
            return;
        }
        data[tail]=elem;
        tail++;
        if(tail==data.length){
            tail=0;
        }
        size++;
        //put后 队列中有元素了 释放take中的wait(如果有的话)
        this.notify();
    }
    public String take() throws InterruptedException {
        if(size==0){
            //如果队列空 阻塞等待 直到有元素put
            this.wait();
            return null;
        }
        String ret=data[head];
        head++;
        if(head==data.length){
            head=0;
        }
        size--;
        //take后 队列中不满了,释放put中的wait(如果有的话)
        this.notify();
        return ret;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值