阻塞队列介绍

阻塞队列

阻塞队列的接口声明形式:

public interface BlockingQueue<E> 
extends Queue<E>

阻塞队列提供了一下方法:

抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e,time,unit)
移除remove(e)poll(e)take(e)poll(time,unit)
检查element(e)peek(e)不可用不可用

put、take方法会产生阻塞,是阻塞队列提供的新的方法阻塞队列特点:
1、集合实例中不能存储null值,否则会抛出空指针或特定的值
2、阻塞队列可以是限定容量,也可以动态扩容
3、阻塞队列是线程安全的集合操作,其内部通过reentrantlock来加锁实现安全

主要实现类

ArrayBlockQueue:有界阻塞队列

    private static final long serialVersionUID = -817911632652898426L;
    //通过数组保存数据
    final Object[] items;
    //读数据位置
    int takeIndex;
    //写数据的位置
    int putIndex;
    //队列存储的个数
    int count;
    //锁
    final ReentrantLock lock;
    //Condition 对象实例进行对象间的通信
    private final Condition notEmpty;
    private final Condition notFull;

ArrayBlockingQueue的实现是用一个数据来存储所有的数据,而且该数据是不可扩大的数组,另外存储两个索引位置,分别是读操作takelndex和写操作
putindex,另外含有存储数据的数量count属性
支持阻塞需要一个锁Lock和两个条件〔非空、非满)

因为是持有一把锁,所以任何对队列操作只有一个线程,所以索引位置和count数量的操作都是线程安全的

构造函数

public ArrayBlockingQueue(int capacity, boolean fair) {
//合法性校验
        if (capacity <= 0)
            throw new IllegalArgumentException();
            //创建数组实例
        this.items = new Object[capacity];
        //创建锁实例
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

put方法

    public void put(E e) throws InterruptedException {
    //检查插入数据是否为null
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        //中断锁
        lock.lockInterruptibly();
        try {
        //当前集合容量满了,需要进入等待
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
        //释放锁
            lock.unlock();
        }
    }

enqueue代码如下:

private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        //直接从堆栈取items的引用,更快
        final Object[] items = this.items;
        //将元素x存放在数组的putIndex位置上
        items[putIndex] = x;
        //如果插入的位置已经是数组中的最后一个位置了,那么就将putIndex置为0
        //因为已经到达最后一个了,那就只能从第一个位置插入元素
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        //唤醒notEmpty队列中等待获取数据的线程
        notEmpty.signal(); 
    }

take方法

  public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lockInterruptibly();
        try {
          //当容量为空时,则阻塞,等待put方法中的notEmpty.signa的通知
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
        //释放锁 
            lock.unlock();
        }
    }

dequeue

 private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
            //通知put可以进行插入
        notFull.signal();
        return x;
    }

LinkedBlockQueue:无界阻塞队列

//容量
private final int capacity;
//记录存储数据的个数
private final AtomicInteger count = new AtomicInteger ( 0 ) ;
//头节点
private transient Node<E> head ;
//下一个节点
private transient Node<E> last;
//创建了一个删除操作锁
private final ReentrantLock takeLock = new ReentrantLock( ) ;
private final Condition notEmpty = takeLock.newCondition ( ) ;
//创建了一个插入的操作锁
private final ReentrantLock putLock = new ReentrantLock( ) ;
private final Condition notFull = putLock.newCondition ( ) ;

1、LinkedBlockingQueue实现上是使用的链表
2、数据存储在Node结构中
3、引入了两把锁,一个入队列锁,一个出队列的锁

put方法

public void put(E e) throws Inter ruptedException {
//插入数据不能为null
if (e == null) throw new NullPointerException();
int c=-1;
Node<E> node = new Node(e) ;
final ReentrantLock putLock = this. putLock;
final AtomicInteger count = this. count;
//添加入队列锁.
putLock. lockInterruptibly();
try {
//当容器满时,当前通知存在两个点会通知
//1、当容量不满时,由put的线程通知
//2、当容量满时,由take的线程通知
while (count.get() == capacity) {
notFull. await() ;
}
//将节点插入到链表尾部
enqueue(node);
//原子性的++操作
c = count.getAndIncrement();
//通知take出队列的notFull. signal操作
if (c + 1 < capacity)
notFull.signal();
} finally {
//释放入队列锁
putLock. unlock();
}
if(c==0)
signalNotEmpty();
}

SychronousQueue:同步阻塞队列

同步队列,每一个插入操作必须等待两一个线程的移除操作,同样,一个线程的移除操作必须等待另一个线程的插入操作元素是不会做停留的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值