【JUC并发】阻塞队列

阻塞队列实现原理

插入和移除操作的处理方式

抛出异常返回特殊值一直阻塞超时退出
插入add(e)offer(e)put(e)offer(e,time,unit)
移除remove()poll()take()poll(time, unit)
检查element()peek()//

通过这两个Condition接口实现

private final Condition notEmpty;	//take()
private final Condition notFull;	//put()

当队列不可用时,都是调用的await()方法

如果队列不可用,就先保存当前线程的状态,然后进行通过unsafe包下的park()
进行阻塞

/**
 *	await()方法
 */
public final void await() throws InterruptedException {
    //如果线程被中断
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        //如果队列不可用
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}
/**
 *	park()方法
 */
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    //保存当前线程的状态
    setBlocker(t, blocker);
    //调用底层UNSAFE包下的park()方法,阻塞当前线程。
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}
/**
 * UNSAFE.park()
 */
public native void park(boolean var1, long var2);
ArrayBlockingQueue(有界,长度为用户传入的)

存储格式(用数组的形式存储数据)

//元素数组
final Object[] items;
//获取元素的下标
int takeIndex;
//添加元素的下标
int putIndex;
//数组中元素的个数
int count;

初始化

/**
 * 初始化阻塞队列
 */
public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    //定义数组长度
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    
    //使用的是Condition
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}

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();
    }
}
private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    //唤醒,队列不空
    notEmpty.signal();
}

take()方法

/**
 *	取元素
 */
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}
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();
    //唤醒,队列不满
    notFull.signal();
    return x;
}
LinkedBlockingQueue(有界,默认为0x7fffffff)

存储格式(用一个Node节点记录数据)

static final class Node<E> {
    //元素
    E item;
    //父节点
    Node<E> prev;
    //子节点
    Node<E> next;
	//构造方法
    Node(E x) {
        item = x;
    }
}
//首节点
transient Node<E> first;
//尾节点
transient Node<E> last;
//节点的个数
private transient int count;

初始化

public LinkedBlockingDeque(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    //队列最大的长度
    this.capacity = capacity;
}

put()方法

public void put(E e) throws InterruptedException {
    putLast(e);
}
public void putLast(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        //当队列中的元素大于等于最大值时,调用await()方法
        while (!linkLast(node))
            notFull.await();
    } finally {
        lock.unlock();
    }
}

take()方法

public E take() throws InterruptedException {
    return takeFirst();
}
public E takeFirst() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E x;
        //当队列为空时,调用await()方法
        while ( (x = unlinkFirst()) == null)
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}
PriorityBlockingQueue(无界,put()方法可能会造成OOM问题)

存储格式

​ 用==数组==的方式进行存储,只实现了一个Condition接口,notEmpty。

put()方法

public void put(E e) {
    offer(e); // never need to block
}
public boolean offer(E e) {
    if (e == null)
    	throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lock();
    int n, cap;
    Object[] array;
    while ((n = size) >= (cap = (array = queue).length))
        //如果元素的长度大于了队列的长度,调用tryGrow(Object[] array, int oldCap)方法,使用新的数组。
    	tryGrow(array, cap);
    try {
    	Comparator<? super E> cmp = comparator;
    	if (cmp == null)
    		siftUpComparable(n, e, array);
    	else
    		siftUpUsingComparator(n, e, array, cmp);
    	size = n + 1;
   	 	notEmpty.signal();
    } finally {
    	lock.unlock();
    }
    return true;
}
/**
 *	tryGrow(Object[] array, int oldCap)方法,可能会造成OOM问题。
 */
private void tryGrow(Object[] array, int oldCap) {
        lock.unlock(); // must release and then re-acquire main lock
        Object[] newArray = null;
    	//如果当前标记的锁为0并且CAS成功
        if (allocationSpinLock == 0 &&
            UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,0, 1)) {
            try {
                //定义一个新的队列长度,新队列长度为:
                //	如果老队列长度小于64:老队列长度+老队列长度+2
                //	如果老队列长度大于等于64:老队列长度+老队列/2的长度
                int newCap = oldCap + ((oldCap < 64) ?
                                       (oldCap + 2) : // grow faster if small
                                       (oldCap >> 1));
                //如果新队列长度大于最大队列长度,可能会发生溢出
                //MAX_ARRAY_SIZE = Integet.MAX_VALUE - 8;
                if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow
                    int minCap = oldCap + 1;
                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
                        //抛出内存溢出错误
                        throw new OutOfMemoryError();
                    newCap = MAX_ARRAY_SIZE;
                }
                //新队列长度大于老队列长度并且队列没发生变化
                if (newCap > oldCap && queue == array)
                    newArray = new Object[newCap];
            } finally {
                //将锁标记改为0
                allocationSpinLock = 0;
            }
        }
        if (newArray == null) // back off if another thread is allocating
            Thread.yield();
        lock.lock();
        if (newArray != null && queue == array) {
            queue = newArray;
            System.arraycopy(array, 0, newArray, 0, oldCap);
        }
    }
SynchronousQueue(不存储元素的阻塞队列,每个put操作必须等待一个take操作,否则不能继续添加元素)

队列本身不存储任何元素

SynchronousQueue吞吐量高于LinkedBlocking和ArrayBlockingQueue

put()方法

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    if (transferer.transfer(e, false, 0) == null) {
        Thread.interrupted();
        throw new InterruptedException();
    }
}
abstract E transfer(E e, boolean timed, long nanos);

take()方法

public E take() throws InterruptedException {
    E e = transferer.transfer(null, false, 0);
    if (e != null)
        return e;
    Thread.interrupted();
    throw new InterruptedException();
}
abstract E transfer(E e, boolean timed, long nanos);
DelayQueue(支持优先级,可以延时获取元素的无界队列)

通过Priority实现,队列中的元素必须实现Delayed接口,只有在延时期满才能获取元素

通过一个Condition实现

private final Condition available = lock.newCondition();
LinkedTransferQueue(无界)

存储格式

链表

LinkedBlockingDeque(双向)

存储格式

链表

可以实现fork/join的工作窃取

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值