Board logo

标题: Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(1) [打印本页]

作者: look_w    时间: 2019-1-11 18:32     标题: Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(1)

Java中的阻塞队列接口BlockingQueue继承自Queue接口。
BlockingQueue接口提供了3个添加元素方法。
3个删除方法。
常用的阻塞队列具体类有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、LinkedBlockingDeque等。
本文以ArrayBlockingQueue和LinkedBlockingQueue为例,分析它们的实现原理。
ArrayBlockingQueueArrayBlockingQueue的原理就是使用一个可重入锁和这个锁生成的两个条件对象进行并发控制(classic two-condition algorithm)。
ArrayBlockingQueue是一个带有长度的阻塞队列,初始化的时候必须要指定队列长度,且指定长度之后不允许进行修改。
它带有的属性如下:

// 存储队列元素的数组,是个循环数组final Object[] items;// 拿数据的索引,用于take,poll,peek,remove方法int takeIndex;// 放数据的索引,用于put,offer,add方法int putIndex;// 元素个数int count;// 可重入锁final ReentrantLock lock;// notEmpty条件对象,由lock创建private final Condition notEmpty;// notFull条件对象,由lock创建private final Condition notFull;



数据的添加ArrayBlockingQueue有不同的几个数据添加方法,add、offer、put方法。
add方法:


public boolean add(E e) {    if (offer(e))        return true;    else        throw new IllegalStateException("Queue full");}


add方法内部调用offer方法如下:


public boolean offer(E e) {    checkNotNull(e); // 不允许元素为空    final ReentrantLock lock = this.lock;    lock.lock(); // 加锁,保证调用offer方法的时候只有1个线程    try {        if (count == items.length) // 如果队列已满            return false; // 直接返回false,添加失败        else {            insert(e); // 数组没满的话调用insert方法            return true; // 返回true,添加成功        }    } finally {        lock.unlock(); // 释放锁,让其他线程可以调用offer方法    }}


insert方法如下:


private void insert(E x) {    items[putIndex] = x; // 元素添加到数组里    putIndex = inc(putIndex); // 放数据索引+1,当索引满了变成0    ++count; // 元素个数+1    notEmpty.signal(); // 使用条件对象notEmpty通知,比如使用take方法的时候队列里没有数据,被阻塞。这个时候队列insert了一条数据,需要调用signal进行通知}




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0