ArrayBlockingQueue源码解读

 
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();
}

ArrayBlockingQueue有3个构造方法,上面是其中一个,另外两个都会调用它。构造方法有两个参数:
capacity,代表队列的长度,构造方法一开始就初始化好了一个长度为capacity的数组,ArrayBlockingQueue内部是一个循环队列,这样一来,用数组存储队列的元素就是最好的选择。
fair,表示是公平锁还是非公平锁,ArrayBlockingQueue内部的线程同步使用ReentrantLock实现,对于公平锁,多个线程获取锁是按照FIFO的顺序获取的,非公平锁则是随机获得的。

ArrayBlockingQueue还有一个初始化的时候就填入数据的构造方法,在这个构造方法中,完成了初始化后,方法会获取锁,进而向队列里添加元素,这个加锁操作是为了保证初始化的可见性。
public ArrayBlockingQueue(int capacity, boolean fair,
                          Collection<? extends E> c) {
    this(capacity, fair);

    final ReentrantLock lock = this.lock;
    lock.lock(); // Lock only for visibility, not mutual exclusion
    try {
        int i = 0;
        try {
            for (E e : c) {
                checkNotNull(e);
                items[i++] = e;
            }
        } catch (ArrayIndexOutOfBoundsException ex) {
            throw new IllegalArgumentException();
        }
        count = i;
        putIndex = (i == capacity) ? 0 : i;
    } finally {
        lock.unlock();
    }
}
ArrayBlockingQueue主要由以下几个重要方法
方法返回或超时返回阻塞     
插入offer(E e) / offer(e, long timeout, TimeUnit unit)put(E e)
移除poll() / poll()poll(long timeout, TimeUnit unit)take()

插入元素

1、offer(E e) / offer(e, long timeout, TimeUnit unit)

offer方法源码

public boolean offer(E e) {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count == items.length)
            return false;
        else {
            enqueue(e);
            return true;
        }
    } finally {
        lock.unlock();
    }
}

offer方法流程如下

1)先对插入的元素进行非空检查,如果为空checkNotNull方法会抛出异常

2)上锁

3)如果队列已满,返回false表示插入元素失败,否则元素入列,返回true表示插入成功

4)在退出方法前,finally块释放锁

可以看见offer方法在插入过程中保证了线程同步,如果队列已满,会使得插入失败,返回false

offer还有另一个重载方法

public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    checkNotNull(e);
    long nanos = unit.toNanos(timeout);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length) {
            if (nanos <= 0)
                return false;
            nanos = notFull.awaitNanos(nanos);
        }
        enqueue(e);
        return true;
    } finally {
        lock.unlock();
    }
}

这个重载方法多了两个参数,实现的是超时退出,如果队列为满,会使得当前线程进入等待状态等待一定的时长,等待期间如果队列不为满了就会被唤醒,然后元素添加成功,如果超过了参数设置的时限队列仍为满,元素就会添加失败,返回false。

2、put(E e)

put方法的源码如下

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

put方法流程如下

1)先对插入的元素进行非空检查,如果为空checkNotNull方法会抛出异常

2)上锁

3)如果队列已满,与offer方法不同的是,这里会调用notFull.await()迫使当前线程进入等待并且释放锁,直到队列不满才会被唤醒并且重新获得锁

4)元素入列

5)释放锁

当队列为满时,offer超时退出实现的是等待一定时间,而put方法就可以让当前线程无限等待。在源码中可以看到,如果队列为满,put方法会无限等待下去,直到线程被唤醒,并且当前队列不为满,新的元素才可以入列。


移除元素

1、poll() / poll()poll(long timeout, TimeUnit unit)

poll 两个方法源码如下

public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return (count == 0) ? null : dequeue();
    } finally {
        lock.unlock();
    }
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0) {
            if (nanos <= 0)
                return null;
            nanos = notEmpty.awaitNanos(nanos);
        }
        return dequeue();
    } finally {
        lock.unlock();
    }
}

poll方法用于元素出列,实现思想类似于offer两个方法,如果队列不为空,队头元素出列,并将其返回。否则返回null,或者等待超时后,如果队列仍为空,返回null。

2、take()

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

take也是元素出列的方法,如果队列为空,没有元素可以出列时,线程会进入等待状态,直至被唤醒,并且队列不为空了,方法


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值