Android并发——阻塞队列,线程池以及AsyncTask

介绍

阻塞队列,线程池与AsyncTask都是Android开发中经常用到的技术,其实这三种技术中是有引用关系的,AsyncTask将Runnable存储在线程池中,线程池内存储Runnable的位置是阻塞队列,接下来我们从下到上了解一下这三者的相关知识。

阻塞队列

简介

阻塞队列常用于生产者-消费者场景。特征为数据满的情况下,生产者生产会被阻塞;数据空的情况下,消费者消费会被阻塞。

BlockingQueue

  • offer(Object):如果可能的话将object加入阻塞队列,返回是否成功,不阻塞当前线程。
  • offer(Object,long timeout,TimeUnit):可以设置等待时间,时间到未能入队则返回false。
  • put(Object):入队,如果没有空间会阻塞直到有空间。
  • poll(time):出队,设置超时时间,时间到未取到返回null。
  • poll(timeout,TimeUnit):?
  • take():出队,队列为空则阻塞直到有数据。
  • drainTo():一次性获取所有可用的数据对象。

Java中的阻塞队列

  • ArrayBlockingQueue:数组组成的有界阻塞队列
  • LinkedBlockingQueue:链表组成的有界阻塞队列
  • PriorityBlockingQueue:支持优先级的无界阻塞队列
  • DelayQueue:使用优先级队列实现的无界阻塞队列
  • SyncchronousQueue:不存储元素的阻塞队列
  • LinkedTransferQueue:由链表组成的无界阻塞队列
  • LinkedBlockingDeque:由链表组成的双向阻塞队列

下面介绍几个将要用到的阻塞队列
1.ArrayBlockingQueue
数组实现的有界阻塞队列,按照先进先出的原则对元素进行排序,默认不保证公平访问队列(不保证队列可用时按照阻塞顺序访问),也可以手动创建公平队列:

//第一个参数是队列容量,第二个参数为true则为创建公平队列
ArrayBlockingQueue fairQueue=new ArrayBlockingQueue(2000,true);

2.LinkedBlockingQueue
使用链表实现的有界阻塞队列,和ArrayBlockingQueue功能类似。它对与生产者与消费者采用的独立控制的锁来控制同步,使得数据可以并行的读取和写入。在构造函数里应该指定阻塞队列的大小,如果未指定,则大小为Integer.MAX_VALUE。
3.PriorityBlockingQueue
支持优先级的无界阻塞队列,默认采用自然顺序升序排列,可以使用compareTo()方法来控制数据的排序规则,但不能保证同级元素的顺序。
4.DelayQueue
支持延迟的无界阻塞队列,队列中的元素必须实现Delayed接口,创建元素时可以指定元素到期时间,只有到期后元素才能被取走。
5.SynchronousQueue
不存储元素的阻塞队列,每个插入操作必须等待一个其他线程的移除操作,反之相同。

ArrayBlockingQueue关键源码解析

为了理解的更深刻些需要看下源码,先看类中定义的成员变量都有啥:

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
   
	/** The queued items 
	*	队列中的元素存储在一个Object数组内。
	*/
    final Object[] items;
    /** items index for next take, poll, peek or remove 
	*	当前队尾下标,出队时使用
	*/
    int takeIndex;
    /** items index for next put, offer, or add 
	*	当前队首下标,入队时使用
	*/
    int putIndex;
    /** Number of elements in the queue 
	*	当前队列中元素的个数
	*/
    int count;
    /*
     * Concurrency control uses the classic two-condition algorithm
     * found in any textbook.
     * 重入锁和等待条件
     */
    /** Main lock guarding all access */
    final ReentrantLock lock;
    /** Condition for waiting takes */
    private final Condition notEmpty;
    /** Condition for waiting puts */
    private final Condition notFull;
}

put方法:

/**
 *	这个方法先获取了锁对象,并进行可中断的锁操作;
 *	检测当前阻塞队列是否已满,如果满了,使用notNull条件进行等待;
 *	如果当前阻塞队列有位置了,则进行入队操作;
 *	方法执行后解锁。
 */
public void put(E e) throws InterruptedException {
   
        Objects.requireNonNull(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条件阻塞的出队线程。
        notEmpty.signal();
    }

take方法:

/**
 *	首先获取锁对象,并且进行可中断的锁操作;
 *	检测阻塞队列为空时,使用notEmpty条件进行阻塞;
 *	队列不为空时则出队;
 *	方法执行后解锁。
 */
public E take() throws InterruptedException {
   
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
   
            while (count == 0)
                notEmpty.await();
            return dequeue()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值