Queeu - Deque - 的简介

看书上讲解OkHttp源码时候,使用到了Deque,看朋友也都在用,这就有必要好好学习一心

转自:
http://blog.csdn.net/buaaroid/article/details/51315860
http://blog.csdn.net/Buaaroid/article/details/51315970


说明:

一 队列:

队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
这与我们生活中的队列是一致的,前面消费,后边插入

二 双端队列:

双端队列,顾名思义,两端都能操作(操作一下吗?),两端都可以进行插入和删除的操作,即:即可在表的前端,进行插入和删除操作,又可以在表后端进行插入和删除操作

三 栗子与应用

在OkHttp3.4.1的源码中,看到了如下的应用

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;

  /** Executes calls. Created lazily. */
  private ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

可见,OkHttp,用ArrayDeque 作为了请求队列,下面,我们来介绍ArrayDeque

1 继承关系
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable

实现了Deque、Cloneable和Serializable接口。实现Cloneable和Serializable接口的主要目的是为了实现克隆和序列化,
继承了AbstractCollection<E> 抽象类

2 成员变量:

ArrayDeque 类中,定义了4个成员变量,代码如下:

 /**
     * The array in which the elements of the deque are stored.
     * The capacity of the deque is the length of this array, which is
     * always a power of two. The array is never allowed to become
     * full, except transiently within an addX method where it is
     * resized (see doubleCapacity) immediately upon becoming full,
     * thus avoiding head and tail wrapping around to equal each
     * other.  We also guarantee that all array cells not holding
     * deque elements are always null.
     */
    transient Object[] elements; // non-private to simplify nested class access

    /**
     * The index of the element at the head of the deque (which is the
     * element that would be removed by remove() or pop()); or an
     * arbitrary number equal to tail if the deque is empty.
     */
    transient int head;

    /**
     * The index at which the next element would be added to the tail
     * of the deque (via addLast(E), add(E), or push(E)).
     */
    transient int tail;

    /**
     * The minimum capacity that we'll use for a newly created deque.
     * Must be a power of 2.
     */
    private static final int MIN_INITIAL_CAPACITY = 8;
  • Object[] elements;
存储deque元素的数组。
deque的容量是这个数组的长度,它总是2的幂。
该数组永远不会变为满,除了在addX方法中暂时调整大小(请参阅doubleCapacity),当它变为满时,
从而避免头部和尾部缠绕在彼此相等。
我们也保证所有不带deque元素的数组单元都是空的。

简言之: Object[] elements 存储元素的 数组
  • transient int head;
在队列head 处的元素的index(索引),即,接下来调用remove() 或 pop()方法来移除的元素的索引,
如果,对列为空,这个值 = tail的值
  • transient int tail;
接下来,调用addlast() 或者 add()方法,加入队尾的元素的index(索引)
  • private static final int MIN_INITIAL_CAPACITY = 8;
我们将用于新创建的deque的最小容量。 必须是2的力量。

总结:
其中elements是元素集合数组,head是指向队首的下标,tail是指向队尾的下一个位置的下标。MIN_INITIAL_CAPACITY定义了在创建队列是,如果有指定长度,而且指定长度小于MIN_INITIAL_CAPACITY,则使用MIN_INITIAL_CAPACITY作为数组的最小长度。

3 构造函数:

构造函数有3,

  • 1 无参构造:
  public ArrayDeque() {
        elements = new Object[16];
    }

默认元素,数组大小 16

  • 2 指定大小的构造:
    public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }

调用了allocateElements(numElements)方法,

 private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)    // Too many elements, must back off
                initialCapacity >>>= 1; // Good luck allocating 2^30 elements
        }
        elements = new Object[initialCapacity];
    }

制定了:元素数组的大小,如果传入的大小,小于MIN_INITIAL_CAPACITY,则使用MIN_INITIAL_CAPACITY作为数组的最小长度。

  • 2 指定元素构造:
    public ArrayDeque(Collection<? extends E> c) {
        allocateElements(c.size());
        addAll(c);
    }

传入一个元素集合,这个构造内部完成了:构造Object[] 数组,和填充元素的操作

4 常用方法:

这里要从Queue接口开始写起:
转自 : http://blog.csdn.net/Buaaroid/article/details/51315970

5 . Queue

在java5中新增加了Java.util.Queue接口,用以支持队列的常见操作。该接口扩展了java.util.Collection接口。

public interface Queue<E> extends Collection<E> {
      //...
}

所以除了基本的Collection操作,队列还支持:插入,提取和检查操作

  • 类结构
collection类结构.png
Queue类结构.png
:抛异常: :返回特殊值:
插入 add(e) offer(e)
移除 remove() pool()
检查 element() peek()

队列通常(但并非一定)以 FIFO(first in first out 先进先出)的方式排序各个元素。不过优先级队列和 LIFO(last in first out 后进先出) 队列(或堆栈)例外,优先级队列根据提供的比较器或元素的自然顺序对元素进行排序,LIFO队列按 LIFO的方式对元素进行排序。

在 FIFO 队列中,所有的新元素都插入队列的末尾,移除元素从队列头部移除。

Queue使用时要尽量避免Collectionadd()remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常如果要使用前端而不移出该元素,使用element()或者peek()方法。

返回值 方法名 说明
增加
boolean add(E e) 是Collection接口里的方法,将指定元素插入此队列的tail(如果立即可执行,且不会违反容量限制),在成功时返回true,如果当前没有可用空间,则抛出IllegalStateException
boolean offer(E e) 是Queue接口里的方法,将指定元素插入此队列的tail(如果立即可执行,且不会违反容量限制),返回true,否则返回false, 当使用有容量限制的队列时,此方法通常要优于add(E),add(e)方法可能无法插入,抛出异常,
检查
E element() 是Queue接口里的方法,返回head(队头),处的元素,但不移除此元素,如果队列empty,则抛出异常
E peek() 是Queue接口里的方法,返回head(队头),处的元素,但不移除此元素,如果队列empty,则返回null
移除
E remove() 是Queue接口里的方法,(注意,Collection里的remove(E e )方法,是有参的),获取并移除此队列的head,如果队列empty,则抛出异常NoSuchElementException
E poll() 是Queue接口里的方法,(注意,Collection里的remove(E e )方法,是有参的),获取并移除此队列的head,如果队列empty,则返回null

说明:

offer 方法可插入一个元素,否则返回 false。这与 Collection.add 方法不同,该方法只能通过抛出未经检查的异常使添加元素失败。

remove() 和 poll() 方法可移除和返回队列的头。到底从队列中移除哪个元素是队列排序策略的功能,而该策略在各种实现中是不同的。remove() 和 poll() 方法仅在队列为空时其行为有所不同:remove() 方法抛出一个异常,而 poll() 方法则返回 null。

element() 和 peek() 返回,但不移除,队列的头。

Queue 实现通常不允许插入 null 元素,尽管某些实现(如 LinkedList)并不禁止插入 null。即使在允许 null 的实现中,也不应该将 null 插入到 Queue 中,因为 null 也用作 poll 方法的一个特殊返回值,表明队列不包含元素。

值得注意的是LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

 private void testDeque() {

        Deque<String> tmpDeque = new LinkedList<>();
        tmpDeque.offer("Hello");
        tmpDeque.offer("World");
        tmpDeque.offer("你好!");
        Log.d(TAG, "tmpDeque.size():" + tmpDeque.size());
        String str = null;
        while ((str = tmpDeque.poll()) != null) {
            Log.d(TAG, "str : " + str);
        }
        Log.d(TAG, "tmpDeque.size():" + tmpDeque.size());
    }

 D/DequeActivity: tmpDeque.size():3
 D/DequeActivity: str : Hello
 D/DequeActivity: str : World
 D/DequeActivity: str : 你好!
 D/DequeActivity: tmpDeque.size():0

6 . Deque

public interface Deque<E> extends Queue<E> {
          //....
}

Deque 接口继承了Queue接口,所以支持Queue 的所有操作,间接也支持Collection的所以操作

类节构:

deque类结构.png

Deque是一个线性 collection,支持在两端插入和移除元素。
名称 deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。

大多数 Deque 实现对于它们能够包含的元素数没有固定限制,但此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。

deque1.jpg

此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。因为此接口继承了队列接口Queue,所以其每种方法也存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

  • 将Deque 用作单纯的队列(FIFO,尾进头出,先进先出)

在将双端队列用作队列时,将得到 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。从 Queue 接口继承的方法完全等效于 Deque 方法,如下表所示:

Queue的方法 等效Deque的方法 描述
add(E e) addLast(E e) 添加至tail,失败,则抛异常
offer() offerLast() 添加至tail,失败,则返回false
remove() removeFirst() 移除head,失败,则抛异常
poll() pollFirst() 移除head,失败,返回null
element() getFirst() 检查head,不移除,失败,则抛异常
peek() peekFirst() 检查head,,不移除,失败,则返回null
deque2.jpg
  • 将Deque 用作栈(LIFO,头进头出,后进先出,比如activity的栈)

在将双端队列用作 LIFO(后进先出)堆栈。应优先使用此接口而不是遗留 Stack 类。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法完全等效于 Deque 方法,如下表所示:

堆栈方法 等效Deque的方法 描述
push(e) addFirst(e) 添加至头部,失败,则抛异常
offerFirst(e) 添加至头部,失败,则返回false
pop() removeFirst() 移除头部,失败,则抛异
pollFirst() 移除头部,失败,则返回false
peek() getFirst() 检查头部,失败,则抛异常
peekFirst() 检查头部,失败,则返回null
deque3.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,590评论 18 139
  • 栈 栈的英文单词是Stack,它代表一种特殊的线性表,这种线性表只能在固定一端(通常认为是线性表的尾端)进行插入,...
    Jack921阅读 1,492评论 0 5
  • 容器的概念所谓STL容器,即是将最常运用的一些数据结构(data structures)实现出来。容器是指容纳特定...
    饭饭H阅读 374评论 0 0
  • 译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.j...
    高广超阅读 5,073评论 1 68
  • 集合框架体系概述 为什么出现集合类?方便多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方法. 数组...
    acc8226阅读 768评论 0 1