实现阻塞队列

本文介绍了Java中的阻塞队列接口BlockingQueue及其几个实现类,重点讲解了ArrayBlockQueue的实现原理,并展示了如何通过数组实现一个简单的阻塞队列。在实现过程中,通过wait和notify方法实现了在队列满和空时的阻塞与唤醒,确保了线程安全。最后讨论了如何处理head==tail的情况,以及在多线程环境下确保线程安全的策略。
摘要由CSDN通过智能技术生成

阻塞队列就是能够

在队列为空时,从队列里取出元素的操作将被阻塞。

当队列为满时,向队列中添加元素的操作会被阻塞。

 Java中也向我们提供了对应的集合类,BlockingQueue阻塞队列属于一个接口,它的底层有七个实现类:

  • ArrayBlockQueue:由数组结构组成的有界阻塞队列
  • LinkedBlockingQueue:由链表结构组成的有界(但是默认大小 Integer.MAX_VALUE)的阻塞队列
    • 有界,但是界限非常大,相当于无界,可以当成无界
  • PriorityBlockQueue:支持优先级排序的无界阻塞队列
  • DelayQueue:使用优先级队列实现的延迟无界阻塞队列
  • SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列
    • 生产一个,消费一个,不存储元素,不消费不生产
  • LinkedTransferQueue:由链表结构组成的无界阻塞队列
  • LinkedBlockingDeque:由链表结构组成的双向阻塞队列

 我们通过代码实现一个ArrayBlockQueue

实现:

阻塞队列的特点,阻塞队列首先我们就要使用数组实现一个环形队列

环形队列实现的核心就在于,如何解决head==tail时到底是满了还是空的问题。

一般有三种解决方式:

1、设置一个标志位,如果第一次遇到的时候设置为false,第二次遇到就能够区分。

2、多设一个空位,浪费一个数组空间,这时判满就可以使判断满和判断空的条件区分开。

3、多设置一个成员变量size,size==elem.length时就是满 ,size==0时为空。

这里我们使用最简单的方式,也就是第三种。

class MyBlockQueue{
    private int[] elem=new int[1000];
    private int head=0;
    private int tail=0;
    private int size=0;

    public void put(int data){
        if(this.size==this.elem.length){
            return ;
        }
        this.elem[tail++]=data;
        this.size++;
        if(this.tail>=this.elem.length){
            this.tail=0;
        }
    }
    public int take(){
        if(this.size==0){
            return 0;
        }
        int ret=this.elem[head++];
        this.size--;
        if(this.head>=this.elem.length){
            this.head=0;
        }
        return ret;
    }
}

 然后要实现的就是阻塞功能:

阻塞功能就是

在队列为空时,从队列里取出元素的操作将被阻塞。

当队列为满时,向队列中添加元素的操作会被阻塞。

所以我们当队列满的时候就让该线程调用wait方法阻塞,当取出完元素的时候就把该线程调用notify唤醒。

同样的当队列空时调用wait阻塞,当添加完元素的时候就把该线程调用notify唤醒。

class MyBlockQueue{
    private int[] elem=new int[1000];
    private int head=0;
    private int tail=0;
    private int size=0;

    public void put(int data) throws InterruptedException {
        if(this.size==this.elem.length){
            this.wait();
        }
        this.elem[tail++]=data;
        this.size++;
        if(this.tail>=this.elem.length){
            this.tail=0;
        }
        this.notify();
    }
    public int take() throws InterruptedException {
        if(this.size==0){
            this.wait();
        }
        int ret=this.elem[head++];
        this.size--;
        if(this.head>=this.elem.length){
            this.head=0;
        }
        this.notify();
        return ret;
    }
}

实现线程安全

如果有多个线程同时调用take方法时,可能还会出现bug。我们把take操作加上锁,这样就实现线程安全了。这就是线程安全的阻塞队列。

class MyBlockQueue{
    private int[] elem=new int[1000];
    private int head=0;
    private int tail=0;
    private int size=0;

    public void put(int data) throws InterruptedException {
        synchronized (this){
            if(this.size==this.elem.length){
                this.wait();
            }
            this.elem[tail++]=data;
            this.size++;
            if(this.tail>=this.elem.length){
                this.tail=0;
            }
            this.notify();
        }
    }
    public int take() throws InterruptedException {
        synchronized (this){
            if(this.size==0){
                this.wait();
            }
            int ret=this.elem[head++];
            this.size--;
            if(this.head>=this.elem.length){
                this.head=0;
            }
            this.notify();
            return ret;
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东莞呵呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值