Java阻塞队列

阻塞队列

1. 什么是阻塞队列?

阻塞队列,顾名思义,它就是一个队列,其在并发情况下,在队列的基础上可以实现**“阻塞”**功能

  • 阻塞队列满的时候,向队列中插入元素的线程将被阻塞,直到其他线程从队列中取出元素
  • 阻塞队列为空的时候,从队列中取出元素的线程被阻塞,直到其他线程向队列中插入元素

image-20210804214015890

如上图所示,如果队列已满,线程1将被阻塞,无法put(插入)元素,如果队列为空,线程2将被阻塞,无法take(取出)元素。

2.为什么使用阻塞队列?

在并发情况下,我们可以不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切阻塞队列会根据线程情况自己决定,就不需要程序员来一直控制。

3. 阻塞队列代码实现

class BlockingQueueDemon
{
    private int[] array = new int[10];
    //初始化头尾位置及数组大小
    private volatile int head = 0;
    private volatile int tail = 0;
    private volatile int size = 0;

    /**
     * 阻塞队列入队列
     * @param value
     */
    public void put(int value) throws InterruptedException
    {
        synchronized (this)
        {
            //如果队列满了,阻塞入队列操作,等下面的出队列操作调用notify方法后才可移执行
            if (array.length == size)
            {
                wait();
            }
            array[tail++] = value;
            //保证循环队列,如果队尾已到数组最大长度,将会把下个元素从0开始再次循环
            if (tail == array.length)
            {
                tail = 0;
            }
             //入队列,队列元素加1
            size++;
            notify();//唤醒出队列操作
        }
    }

    /**
     * 阻塞队列出队列
     */
    public int take() throws InterruptedException
    {
        int ret;
        synchronized (this)
        {
            //如果队列为空,阻塞等待,等到入队列再开始
            if (size == 0)
            {
                wait();
            }
            ret = array[head++];
            //保证循环队列,如果队首已到数组最大长度,将会把下个元素从0开始再次循环
            if (head == array.length)
            {
                head = 0;
            }
            //出队列,队列元素减1
            size--;
            notify();//唤醒入队列操作
        }
        return ret;
    }
}

4. 代码分析

如下图所示

  • 当队列已满时(array.length = size),如果有线程调用put方法,其将执行wait方法,使当前插入操作的线程阻塞,直到其他线程调用take方法,取出元素后,其中的notify方法将唤醒 阻塞的put方法 线程,才可以执行put后续的插入操作。
  • 当队列为空时(size == 0),如果有线程调用take方法,其将执行wait方法,使当前取出操作线程阻塞,直到其他线程调用put方法,插入元素后,其中的notify方法将唤醒 阻塞的take方法 线程,才可以执行take后续的取出操作。

image-20210804215958732

5. JDK内置的阻塞队列

名称描述
ArrayBlockingQueue由数组结构组成的有界阻塞队列
LinkedBlockingQueue由链表结构组成的有界(但大小默认值为Integer.Max_Value)阻塞队列
SynchronousQueue不存储元素的阻塞队列,也即单个元素的队列

6. 阻塞队列的方法

6.1 插入操作

add(e) :添加元素到队列中,如果队列满了,继续插入元素会报错,IllegalStateException。

offer(e) : 添加元素到队列,同时会返回元素是否插入成功的状态,如果成功则返回 true

put(e) :当阻塞队列满了以后,生产者继续通过 put添加元素,队列会一直阻塞生产者线程,直到队列可用

offer(e,time,unit) :当阻塞队列满了以后继续添加元素,生产者线程会被阻塞指定时间,如果超时,则线程直接退出

6.2 取出操作

remove():当队列为空时,调用 remove 会返回 false,如果元素移除成功,则返回 true

poll(): 当队列中存在元素,则从队列中取出一个元素,如果队列为空,则直接返回 null

take基于阻塞的方式获取队列中的元素,如果队列为空,则 take 方法会一直阻塞,直到队列中有新的数据可以消费

poll(time,unit):带超时机制的获取数据,如果队列为空,则会等待指定的时间再去获取元素返回

null

take基于阻塞的方式获取队列中的元素,如果队列为空,则 take 方法会一直阻塞,直到队列中有新的数据可以消费

poll(time,unit):带超时机制的获取数据,如果队列为空,则会等待指定的时间再去获取元素返回

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值