【java并发】阻塞队列BlockingQueue

前言

java.util.concurrent.BlockingQueue:顾名思义,它是一个并发操作队列数据线程安全(JUC)的阻塞队列。阻塞出现在多个场景下,如队列满了则插入阻塞,如果队列空了则提取阻塞,也有可能插入队列操作执行时提取操作阻塞,各个子类的实现不一样。

1 BlockingQueue概览

public interface BlockingQueue<E> extends Queue<E> {

    //看注释是添加元素到队列中,成功返回true,如果失败了,则抛出异常?可是接口没定义呀?
    //查看多个子类发现都没有实现该方法,这是什么情况?
    //查看抽象类AbstractQueue,发现实现在这:
    //if (offer(e)) return true; else throw new IllegalStateException("Queue full");
    boolean add(E e);

    //添加元素到队列中,成功返回true,失败返回false
    boolean offer(E e);

    //添加元素到队列中,如果没有可用空间则阻塞等待
    void put(E e) throws InterruptedException;

    //给定时间内进行添加元素操作,成功返回true,超时失败返回false
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;

    //提取元素并从队列移除,如果操作失败则等待,直到该操作成功
    E take() throws InterruptedException;

    //提取元素并从队列移除,如果操作失败则等待一定时间,超时后返回null
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

    //获取队列空闲容量
    int remainingCapacity();

    //从队列中移除所有与传参对象‘equals’的对象
    boolean remove(Object o);

    //判断队列中是否包含与传参对象‘equals’的对象
    public boolean contains(Object o);

    //将队列中值移除,并剪切到传参集合中
    int drainTo(Collection<? super E> c);

    //将队列中指定数量(maxElements)的值移除,并剪切到传参集合中
    int drainTo(Collection<? super E> c, int maxElements);
}

IDEA类图展示:四个常见阻塞队列(红框)+一个非阻塞队列ConcurrentLinkedQueue(蓝框)

2 四小强介绍(Array,Linked,Sync,Delay)

  • 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();
}
  • LinkedBlockingQueue:一个由链表结构组成的无界队列,无界指默认可以不设置容量,即容量为Integer.MAX_VALUE,上代码
//链表结构
static class Node<E> {
	E item;
	Node<E> next;
	Node(E x) { item = x; }
}
//首尾节点
transient Node<E> head;
private transient Node<E> last;

//读写锁分离
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
  • SynchronousQueue:一个不存储元素的阻塞队列,每一次put数据必须等待take数据,反之也是如此。相当于取消了中介,生产者直接将数据传递给消费者,这在多任务并发消费时,具有非常不错的性能。那么队列核心所需要管理的就不是数据,而是生产线程和消费线程,管理方式包含公平模式(FIFO队列)和非公平模式(LIFO栈,默认)。它常用于线程池的缓存队列。
/**
* Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
	this(false);
}
/**
* Creates a {@code SynchronousQueue} with the specified fairness policy.
*
* @param fair if true, waiting threads contend in FIFO order for
*        access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) {
	transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
  • DelayQueue:一个实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。常见应用常见:各类缓存池、定时任务等;
public E take() throws InterruptedException {
	final ReentrantLock lock = this.lock;
	lock.lockInterruptibly();
	try {
	    for (;;) {
		E first = q.peek();
		//队列头部为空,则等待
		if (first == null)
		    available.await();
		else {
		    long delay = first.getDelay(NANOSECONDS);
		    //如果数据到期了则返回当前数据
		    if (delay <= 0)
			return q.poll();
		    first = null; // don't retain ref while waiting
		    //如果leader线程非空,则继续等待available条件
		    if (leader != null)
			available.await();
		    else {
			Thread thisThread = Thread.currentThread();
			leader = thisThread;
			try {
			    //等待剩余时间
			    available.awaitNanos(delay);
			} finally {
			    if (leader == thisThread)
				leader = null;//重新置空
			}
		    }
		}
	    }
	} finally {
	    if (leader == null && q.peek() != null)
		available.signal();//唤醒
	    lock.unlock();
	}
}

3 并发非阻塞队列-ConcurrentLinkedQueue

一个适用于高并发场景下的队列,通过无锁(CAS实现线程安全)的方式,保证了高并发状态下的高性能。看看添加代码:

public boolean offer(E e) {
	checkNotNull(e);
	final Node<E> newNode = new Node<E>(e);

	for (Node<E> t = tail, p = t;;) {
	    Node<E> q = p.next;
	    if (q == null) {
		// p is last node
		if (p.casNext(null, newNode)) {
		    // Successful CAS is the linearization point
		    // for e to become an element of this queue,
		    // and for newNode to become "live".
		    if (p != t) // hop two nodes at a time
			casTail(t, newNode);  // Failure is OK.
		    return true;
		}
		// Lost CAS race to another thread; re-read next
	    }
	    else if (p == q)
		// We have fallen off list.  If tail is unchanged, it
		// will also be off-list, in which case we need to
		// jump to head, from which all live nodes are always
		// reachable.  Else the new tail is a better bet.
		p = (t != (t = tail)) ? t : head;
	    else
		// Check for tail updates after two hops.
		p = (p != t && t != (t = tail)) ? t : q;
	}
}
//通过cas向队列末尾添加元素       
private boolean casTail(Node<E> cmp, Node<E> val) {
	return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
}

 


爱家人,爱生活,爱设计,爱编程,拥抱精彩人生!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqchaozai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值