当前位置: 首页 > news >正文

淄博乐达网站建设吧wordpress判断页面

淄博乐达网站建设吧,wordpress判断页面,wordpress后端,php网站后台开发一 概述 简介 LinkedBlockingDeque#xff08;链接阻塞双端队列#xff09;类#xff08;下文简称链接阻塞双端队列#xff09;是BlockingDeqeue#xff08;阻塞双端队列#xff09;接口的唯一实现类#xff0c;采用链表的方式实现。链接阻塞双端队列与LinkedBlockingQu…一 概述 简介 LinkedBlockingDeque链接阻塞双端队列类下文简称链接阻塞双端队列是BlockingDeqeue阻塞双端队列接口的唯一实现类采用链表的方式实现。链接阻塞双端队列与LinkedBlockingQueue链接阻塞队列类在实现上基本一致但在其基础上新增了针对队列头部进行插入/放置及针对队列尾部进行移除/拿取、检查等操作的方法及其实现。通俗的讲就是链接阻塞双端队列支持在两端进行插入/放置、移除/拿取、检查等操作而不同于LinkedBlockingQueue链接阻塞队列类必须强制在某端进行。这就使得链接阻塞双端队列相较于LinkedBlockingQueue链接阻塞队列类而言有着更高的灵活性令其可被用于模拟堆栈或其它数据结构。涉及到两端操作的相关方法由BlockingDeqeue阻塞双端队列接口或Deqeue双端队列接口负责定义该知识点的详细内容会在下文详述。 链接阻塞双端队列不允许保存null。不允许保存null实际上是BlockingQueue阻塞队列接口的定义BlockingDeqeue阻塞双端队列接口作为其子接口也同样遵循该定义并延续到了链接阻塞双端队列中。不允许保存null的具体原因是因为null被poll()及peek()等方法作为了表示队列中不存在元素的特殊值。 链接阻塞双端队列支持有界及无界两种使用方式即是否人为限制可保存的元素总数。如果在创建链接阻塞双端队列时没有指定具体容量则其便为无界队列。我们并不推荐使用无界队列由于元素可无限制保存的原因一旦元素的移除/拿取速率低于其插入/放置的速率则很容易导致元素大量堆积造成内存溢出错误。因此在实际开发中还是推荐指定容量的有界队列用法并根据业务的实际场景及资源的硬性限制选择合适的容量大小。此外链接阻塞双端队列在无界队列的实现上并不纯粹采用的是通过Integer.MAX_VALUE大小的有界队列来模拟无界队列的方式这在一定程度上违背了无界队列的实现规范该知识点的详细内容会在下文详述。 链接阻塞双端队列是线程安全的。线程安全实际上是BlockingQueue阻塞队列接口的定义BlockingDeqeue阻塞双端队列接口作为其子接口也同样遵循该定义并延续到了链接阻塞双端队列中。与LinkedBlockingQueue链接阻塞队列类支持更高并发的“双锁”线程安全机制不同链接阻塞双端队列采用常规的“单锁”线程安全机制即使用一个ReentrantLock可重入锁类对象来保证整体的线程安全这实际是引入两端操作所带来的负面影响。两端操作的引入打破了阻塞队列插入/放置与移除/拿取方法之间原本头尾隔离的元素布局使得链接阻塞双端队列中的元素数据成为了一个整体从而不再适用“双锁”线程安全机制。 链接阻塞双端队列实现了正/倒序两类迭代器并且它们都是弱一致性的即可能迭代到已移除的元素或迭代不到新插入的元素。正/倒序两类迭代器的存在很好的契合了两端操作的执行而弱一致性则有效兼容了并发的使用环境使得移除/拿取方法的执行不会导致迭代的异常中断该知识点的详细内容会在下文详述。 链接阻塞双端队列虽然与BlockingQueue阻塞队列接口一样都被纳入Executor执行器框架的范畴但同时也是Collection集框架的成员。 结构 与LinkedBlockingQueue链接阻塞队列类的对比 链接阻塞双端队列支持在两端执行插入/放置、移除/拿取、检查及内部移除等操作而LinkedBlockingQueue链接阻塞队列类只支持在指定端执行链接阻塞双端队列使用“单锁”线程安全机制而LinkedBlockingQueue链接阻塞队列类使用支持更高并发的“双锁”线程安全机制链接阻塞双端队列的底层链表使用了哨兵节点而LinkedBlockingQueue链接阻塞队列类没有使用哨兵节点链接阻塞双端队列的实现了正/倒序两种迭代器而LinkedBlockingQueue链接阻塞队列类只实现了正序迭代器链接阻塞双端队列的正/倒序迭代器进行迭代移除时无需遍历底层链表因为节点保存前驱/后继引用而LinkedBlockingQueue链接阻塞队列类的节点值保存了后继引用因此迭代器进行迭代移除时需要先通过遍历找到迭代元素的前驱节点后才能执行移除。 方法的不同形式 方法的不同形式实际上是BlockingQueue阻塞队列接口的定义链接阻塞双端队列只是继承了这个定义而已。所谓方法的不同形式是指方法在保证自身核心操作不变的情况下实现了多种不同的回应形式来应对不同场景下的使用要求。例如对于插入当容量不足时有些场景希望在失败时抛出异常而有些场景则希望能直接返回失败的标记值而有些场景又希望可以等待直至有可用空间后成功新增为止…正因如此BlockingQueue阻塞队列接口特意提供了四种不同的形式风格以满足不同场景下的使用需求因此一个方法最多并非所有方法都实现了四种形式可能有四种不同回应形式。具体四种回应形式如下 异常当不满足操作条件时直接抛出异常特殊值当不满足操作条件时直接返回失败标记值。例如之所以不允许存null值就是因为null被作为了获取操作失败时的标记值阻塞无限等待当不满足操作条件时无限等待直至满足操作条件后执行超时有限等待当不满足操作条件时有限等待如果在指定等待时间之前直至满足操作条件则执行否则返回失败标记值。 二 创建 public LinkedBlockingDeque(int capacity) —— 创建一个指定容量的“有界”链接阻塞双端队列。该构造方法是现实中使用最多也是最推荐使用的构造方法。优点在于其容量由开发者预先指定最大程度的贴合了业务的实际场景及资源的硬性限制。 public LinkedBlockingDeque() —— 创建一个容量为Integer.MAX_VALUE的“无界”链接阻塞双端队列。现实开发中我们不推荐该构造方法容易导致内存溢出错误OOM。 public LinkedBlockingDeque(Collection? extends E c) —— 创建一个容量为Integer.MAX_VALUE并按迭代器顺序包含指定集中所有元素的“无界”链接阻塞双端队列。既然是无界队列那自然也是不推荐使用的但该方法在实现上也有值得一说的地方。具体源码及注释如下 /*** Creates a {code LinkedBlockingDeque} with a capacity of {link Integer#MAX_VALUE}, initially containing the elements of the given* collection, added in traversal order of the collections iterator.* 创建一个容量为Integer#MAX_VALUE初始包含指定集中所有元素链接阻塞双端队列元素的新增按指定集迭代器顺序。** param c the collection of elements to initially contain 用于初始包含的元素的集* throws NullPointerException if the specified collection or any of its elements are null* 空指针异常如果指定集或其任意元素为null* Description: 名称~* Description: 作用创建一个容量为Integer.MAX_VALUE并按迭代器顺序包含指定集中所有元素的链接阻塞双端队列该链接阻塞* Description: 双端队列被视为无界队列。* Description: 逻辑方法在按迭代器顺序将指定集中元素加入当前链接阻塞双端队列的过程中会加悲观锁。加锁的目的并不是为了避免* Description: 竞争而是确保添加的元素对其它线程可见。*/ public LinkedBlockingDeque(Collection? extends E c) {this(Integer.MAX_VALUE);// Never contended, but necessary for visibility// 不竞争但是为了「元素的」可见性是必要的final ReentrantLock lock this.lock;lock.lock();try {for (E e : c) {if (e null)throw new NullPointerException();// 将指定集中的元素按迭代器顺序从双端队列的尾部依次加入。if (!linkLast(new NodeE(e)))throw new IllegalStateException(Deque full);}} finally {lock.unlock();} }我们可以在上述的源码中发现将指定集中的元素存入链接阻塞双端队列的整个过程是加了锁的而源码给出的英文注释是“没有竞争但为了可见性有必要加锁”。其中本人对可见性是可以理解的如果理解没有错的话如果在过程中没有加锁就会出现并发中其它线程获取到节点但获取不到元素的情况即节点中不包含元素。为什么会出现这样的问题呢这是因为在Java中对象的创建不是原子操作整个过程按顺序大致可分为以下三部分 实例化分配内存初始化执行构造方法引用赋值令变量持有对象的引用。 但现实中由于指令重排序的原因具体在执行中顺序就可能变成 实例化分配内存引用赋值令变量持有对象的引用初始化执行构造方法。 这就意味着加入到链接阻塞双端队列中的节点可能是个空节点即还未完成初始化的过程。如此一来如果有线程在链接阻塞双端队列构造方法执行结束后获取元素则其获取到的节点中元素完全可能是空的因此整个过程必须在锁的保护下执行。锁的存在虽然无法避免同步块中的指令重排序但可以避免其重排序到同步块外这就使得节点的初始化一定会在同步块中完成确保队列创建完成后其它线程获取到的节点一定是完整的存在元素的。 如果上述我的理解都是对的那就有一个讲不通的地方就是既然对象的创建不是原子操作那么在不加锁的情况下完全可能存在有线程向一个未执行初始化或未执行完初始化的链接阻塞双端队列保存元素的可能如此应该是可能存在竞争的而不是英文注释中说的“没有竞争”这也是我目前尚未完全理解的地方…当然也可能是我对可见性的理解本就是错的希望有懂的同学能在评论区不吝赐教本人万分感谢。 无界队列 上文已经提及过链接阻塞双端队列在无界队列的实现上并不纯粹观察上述罗列的构造方法其实也可以看出链接阻塞双端队列的无界队列用法实质上是通过有界队列用法模拟实现的。通过创建一个指定容量为Integer.MAX_VALUE的有界队列确实可以达到与无界队列基本一致的效果从而简化了链接阻塞双端队列的实现但由于该方案毕竟不是无界队列的标准实现故而如此获得的“无界”队列与真正的无界队列还是存在部分差异的。 标准无界队列的容量只受限于堆内存的大小。当然这是逻辑上的说法在实现中其可能会受到具体的物理限制例如int类型的空间制约但这属于被动情况并且当触发该类限制时也会模拟堆内存不足的场景手动抛出内存溢出错误来掩盖真实原因。除此之外BlockingQueue阻塞队列接口还规定对于无界队列当获取其剩余容量时需强制返回Integer.MAX_VALUE表示容量无限诸如PriorityBlockingQueue优先级阻塞队列类、DelayQueue延迟队列类及LinkedTransferQueue链接迁移队列类等无界队列在实现上皆是如此。 链接阻塞双端队列的无界队列用法与标准无界队列的差异如下。也正是因为下列几点虽然在说法上称链接阻塞双端队列支持有界及无界两种使用方式但个人一直将之视为纯粹的有界队列。 人为的限制了容量该容量虽然等同于int类型的最大值但由“被动”转为“主动”使得自身性质发生了根本性改变成为了实际的有界队列当元素总数达到Integer.MAX_VALUE时并不会抛出内存溢出错误而是抛出非法状态异常使得真实的异常原因暴露在外。而对于无界队列来说不应该出现这种定义上因为容量不足而抛出的异常获取剩余容量时不会返回Integer.MAX_VALUE表示容量无限而是返回真实的剩余容量。 三 方法 插入/放置 插入/放置是阻塞队列两大最核心也是最常用的方法之一用于向阻塞队列的尾部插入指定元素。链接阻塞双端队列增强了该功能新增了“向阻塞队列的头部插入指定元素”的方法实现并对“向阻塞队列的尾部插入指定元素”的方法实现进行了封装即为了保证命名规范实现了功能相同但名称不同的方法。由于场景的多样性需求链接阻塞双端队列提供了插入/放置方法四种形式的实现以供使用。 public void addFirst(E e) —— 新增首个 —— 向当前链接阻塞双端队列的头部插入指定元素。该方法是头部插入/放置方法“异常”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功否则抛出非法状态异常。 public void addLast(E e) —— 新增最后 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是尾部插入/放置方法“异常”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功否则抛出非法状态异常。 public boolean add(E e) —— 新增 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是插入/放置方法“异常”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则抛出非法状态异常。该方法等价于addLast(E e)方法但存在返回值可由于方法执行失败时会抛出非法状态异常因此该返回值实际上没有任何意义。 public boolean offerFirst(E e) —— 提供首个 —— 向当前链接阻塞双端队列的头部插入指定元素。该方法是头部插入/放置方法“特殊值”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则返回false。 public boolean offerLast(E e) —— 提供最后 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是尾部插入/放置方法“特殊值”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则返回false。 public boolean offer(E e) —— 提供 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是插入/放置方法“特殊值”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则返回false。该方法等价于offerLast(E e)方法。 public void putFirst(E e) throws InterruptedException —— 放置首个 —— 向当前链接阻塞双端队列的头部插入指定元素。该方法是头部插入/放置方法“阻塞”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功否则等待至存在剩余容量为止。 public void putLast(E e) throws InterruptedException —— 放置最后 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是尾部插入/放置方法“阻塞”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功否则等待至存在剩余容量为止。 public void put(E e) throws InterruptedException —— 放置 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是插入/放置方法“阻塞”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功否则等待至存在剩余容量为止。该方法等价于putLast(E e)方法。 public boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException —— 提供首个 —— 向当前链接阻塞双端队列的头部插入指定元素。该方法是头部插入/放置方法“超时”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则在指定等待时间内等待至存在剩余容量超出等待时间则返回false。 public boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException —— 提供最后 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是尾部插入/放置方法“超时”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则在指定等待时间内等待至存在剩余容量超出等待时间则返回false。 public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException —— 提供 —— 向当前链接阻塞双端队列的尾部插入指定元素。该方法是插入/放置方法“超时”形式的实现当链接阻塞双端队列存在剩余容量时插入/放置成功并返回true否则在指定等待时间内等待至存在剩余容量超出指定等待时间则返回false。该方法等价于offerLast(E e, long timeout, TimeUnit unit)方法。 移除/拿取 移除/拿取是阻塞队列两大最核心也是最常用的方法之一用于从阻塞队列的头部移除并获取元素。链接阻塞双端队列增强了该功能新增了“从阻塞队列的尾部移除并获取元素”的方法实现并对“从阻塞队列的头部移除并获取元素”的方法实现进行了封装。移除/拿取方法同样有四种形式的实现。 public E removeFirst() —— 移除首个 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是头部移除/拿取方法中“异常”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则抛出无如此元素异常。 public E removeLast() —— 移除最后 —— 从当前链接阻塞双端队列的尾部移除并获取元素。该方法是尾部移除/拿取方法中“异常”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回尾元素否则抛出无如此元素异常。 public E remove() —— 移除 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是移除/拿取方法中“异常”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则抛出无如此元素异常。该方法等价于removeFirst()方法。 public E pollFirst() —— 轮询首个 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是头部移除/拿取方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则返回null。 public E pollLast() —— 轮询最后 —— 从当前链接阻塞双端队列的尾部移除并获取元素。该方法是尾部移除/拿取方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回尾元素否则返回null。 public E poll() —— 轮询 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是移除/拿取方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则返回null。该方法等价于pollFirst()方法。 public E takeFirst() throws InterruptedException —— 拿取首个 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是头部移除/拿取方法中“阻塞”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则等待至存在元素。 public E takeLast() throws InterruptedException —— 拿取最后 —— 从当前链接阻塞双端队列的尾部移除并获取元素。该方法是尾部移除/拿取方法中“阻塞”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回尾元素否则等待至存在元素。 public E take() throws InterruptedException —— 拿取 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是移除/拿取方法中“阻塞”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则等待至存在元素。该方法等价于takeFirst()方法。 public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException —— 轮询首个 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是头部移除/拿取方法中“超时”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则在指定等待时间内等待至存在元素超出指定等待时间则返回null。 public E pollLast(long timeout, TimeUnit unit) throws InterruptedException —— 轮询最后 —— 从当前链接阻塞双端队列的尾部移除并获取元素。该方法是尾部移除/拿取方法中“超时”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回尾元素否则在指定等待时间内等待至存在元素超出指定等待时间则返回null。 public E poll(long timeout, TimeUnit unit) throws InterruptedException —— 轮询 —— 从当前链接阻塞双端队列的头部移除并获取元素。该方法是移除/拿取方法中“超时”形式的实现当链接阻塞双端队列存在元素时移除/拿取并返回头元素否则在指定等待时间内等待至存在元素超出指定等待时间则返回null。该方法等价于pollFirst(long timeout, TimeUnit unit)方法。 检查 检查也是阻塞队列的常用方法之一用于从阻塞队列的头部获取元素但并不会将元素从阻塞队列中移除属于移除/拿取方法的阉割版。链接阻塞双端队列增强了该功能新增了“从阻塞队列的尾部获取元素”的方法实现并对“从阻塞队列的头部获取元素”的方法实现进行了封装。检查方法同样具备多形式的实现但只有“异常”与“特殊值”两种。 public E getFirst() —— 获取首个 —— 从当前链接阻塞双端队列的头部获取元素。该方法是头部检查方法中“异常”形式的实现当链接阻塞双端队列存在元素时返回头元素否则抛出无如此元素异常。 public E getLast() —— 获取首个 —— 从当前链接阻塞双端队列的尾部获取元素。该方法是尾部检查方法中“异常”形式的实现当链接阻塞双端队列存在元素时返回尾元素否则抛出无如此元素异常。 public E element() —— 元素 —— 从当前链接阻塞双端队列的头部获取元素。该方法是头部检查方法中“异常”形式的实现当链接阻塞双端队列存在元素时返回头元素否则抛出无如此元素异常。该方法等价于getFirst()方法。 public E peekFirst() —— 窥视首个 —— 从当前链接阻塞双端队列的头部获取元素。该方法是头部检查方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时返回头元素否则返回null。 public E peekLast() —— 窥视最后 —— 从当前链接阻塞双端队列的尾部获取元素。该方法是尾部检查方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时返回尾元素否则返回null。 public E peek() —— 窥视 —— 从当前链接阻塞双端队列的头部获取元素。该方法是头部检查方法中“特殊值”形式的实现当链接阻塞双端队列存在元素时返回头元素否则返回null。该方法等价于peekFirst()方法。 迁移 迁移也是阻塞队列的常用方法之一用于将阻塞队列中的元素迁移至指定集中迁移后的元素不再存在于阻塞队列中。为了避免迁移过程中元素丢失问题实现往往会先将元素加入指定集中后再将元素从阻塞队列中移除。 public int drainTo(Collection? super E c) —— 流失 —— 将当前链接阻塞双端队列中的所有元素迁移至指定集中并返回迁移的元素总数。public int drainTo(Collection? super E c, int maxElements) —— 流失 —— 将当前链接阻塞双端队列中的最多指定数量的元素迁移至指定集中并返回迁移的元素总数。 内部移除 内部移除的原始方法定义源自Collection集接口的remove(Object o)方法用于将集中指定元素的首个单例迭代器顺序移除。由于指定元素可能处于集中的任意位置不一定是头/尾因此被称为内部移除。内部移除在队列中并不是常用的方法一是其不符合队列FIFO的数据结构二是各类队列为了提高性能可能会使用各种优化策略而remove(Object o)方法往往无法适配这些策略导致性能较/极差。链接阻塞双端队列增强了内部移除功能在“从阻塞队列中移除指定元素的首个单例”的方法链接阻塞双端队列基础上新增了“从阻塞队列中移除指定元素的最后单例”的方法实现并对“从阻塞队列中移除指定元素的首个单例”的方法实现进行了封装。 public boolean removeFirstOccurrence(Object o) —— 移除首次出现 —— 从当前链接阻塞双端队列中移除指定元素的首个单例移除成功返回true否则返回false。public boolean removeLastOccurrence(Object o) —— 移除最后出现 —— 从当前链接阻塞双端队列中移除指定元素的最后单例移除成功返回true否则返回false。public boolean remove(Object o) —— 移除 —— 从当前链接阻塞双端队列中移除指定元素的首个单例移除成功返回true否则返回false。该方法等价于removeFirstOccurrence()方法。 堆栈 堆栈功能是Deque双端队列接口为了模拟堆栈适配Stack堆栈类而新增的方法定义而链接阻塞双端队列继承并实现了这些定义。 public void push(E e) —— 推送 —— 向当前链接阻塞双端队列的头部插入指定元素。如果存在剩余空间则插入成功否则抛出非法状态异常。该方法等价于addFirst(E e)方法。 public E pop() —— 弹出 —— 从当前链接双端队列的头部移除并获取元素。如果存在元素则返回头元素否则抛出无如此元素异常。该方法等价于removeFirst()方法。 迭代器 常规队列通常只实现了正序从头到尾迭代器而链接阻塞双端队列增强了该功能新增了倒序从尾到头迭代器的实现。 public Iterator iterator() —— 迭代器 —— 获取一个当前链接阻塞双端队列的正序从头到尾迭代器。public Iterator descendingIterator() —— 下降迭代器 —— 获取一个当前链接阻塞双端队列的倒序从尾到头迭代器。 其它 除了上述提及的主要方法之外链接阻塞双端队列还有一些常用方法如下所示 public int size() —— 大小 —— 获取当前链接阻塞双端队列中的元素总数。public int remainingCapacity() —— 剩余容量 —— 获取当前链接阻塞双端队列的剩余容量。public Object[] toArray() —— 转化数组 —— 获取一个按迭代器顺序包含当前链接阻塞双端队列中所有元素的数组。public T[] toArray(T[] a) —— 转化数组 —— 获取一个按迭代器顺序包含当前链接阻塞双端队列中所有元素的泛型数组。如果参数泛型数组长度足以容纳所有元素则令之承载所有元素后返回。并且如果参数泛型数组的长度大于当前链接阻塞双端队列的元素总数则将已承载所有元素的参数泛型数组的size索引位置设置为null表示从当前链接阻塞双端队列中承载的元素到此为止。当然该方案只对不允许保存null元素的集有效。如果参数泛型数组的长度不足以承载所有元素则重分配一个相同泛型且长度与当前链接阻塞双端队列元素总数相同的新泛型数组以承接所有元素后返回。public void clear() —— 清理 —— 移除当前链接阻塞双端队列中的所有元素。 事实上由于链接阻塞双端队列是Collection集接口的实现类因为其也实现了其定义的所有方法例如contains(Object o)、remove(Object o)及 toArray()等。但由于这些方法的执行效率不高并且与链接阻塞双端队列的主流使用方式并不兼容因此一般情况下是不推荐使用的有兴趣的可以去查看源码实现。 四 正/倒序弱一致性迭代器 链接阻塞双端队列实现了正/倒序两类迭代器并且它们都是弱一致性的即可能迭代到已移除的元素或迭代不到新插入的元素。正/倒序两类迭代器的存在很好的契合了两端操作的执行而弱一致性则有效兼容了并发的使用环境使得移除/拿取方法的执行不会导致迭代的异常中断。与LinkedBlockingQueue链接阻塞队列类的迭代器相比链接阻塞双端队列的迭代器最大在于其执行迭代移除时不需要进行遍历这是节点同事保存了前驱/后继引用所带来的附加效果。而LinkedBlockingQueue链接阻塞队列类的节点由于只保存了后继引用因此迭代移除时必须先遍历找到前驱节点后才能执行移除。 事实上除了元素的迭代顺序有所差异外正/倒序迭代器本质上完全相同因此链接阻塞双端队列采用了模板模式来简化正/倒序迭代器的实现。链接阻塞双端队列内部设计了一个迭代器父/超类该迭代器父/超类提供了hasNext()、next()及remove()方法的完整实现但却将元素迭代顺序的选择权交给了子类。子类只需提供“获取指定顺序下的头元素”及“获取指定顺序下指定元素的下个元素”的方法实现就能够快速实现迭代器就如同正/倒序迭代器正是通过重写“获取正/倒序下的头元素”及“获取正/倒序下的指定元素的下个元素”两个方法实现的。 对于迭代器的弱一致性链接阻塞双端队列是通过以下两步操作实现的 迭代器保存了下次迭代节点/元素的快照由于迭代器保存了下次迭代的节点/元素的快照因此即使下次迭代时节点/元素实际已从链接阻塞双端队列中移除迭代器也依然可以返回迭代元素。与之相应的是如果迭代器已判断下次迭代的节点/元素为null则即使插入了新元素也无法被迭代因为迭代器已经判定迭代完整结束。如此一来就实现了弱一致性“可能迭代到已移除的元素或迭代不到新插入的元素”的特点。 节点被移除移除/拿取、内部移除后不会断开前驱/后继引用由于节点不会断开前驱/后继引用因此即使节点已经被判定为下次迭代的节点且被移除移除/拿取、内部移除迭代器依然可以继续通过其持有引用访问到其在链接阻塞双端队列中的首个前驱/后继节点对应倒序/正序迭代从而避免迭代过程的异常中断。由于在迭代器两次迭代之间可能有多个节点被连续的移除多发生于移除/拿取中内部移除的可能性较小因此如果发现前驱/后继节点同样已从链接阻塞双端队列中移除通过查看节点中的元素是否为null判断则需要连续的向前/后遍历直至找到首个存在于链接阻塞双端队列的前驱/后继节点作为下次迭代的节点/元素为止。 虽说通过上述两步操作成功实现了迭代器的弱一致性但与此同时两者也各自带来了一个问题…并且只能解决其中的部分 移除节点/元素可能在迭代器中长期保留可能导致的频繁老年代GC。 移除节点/元素可能在迭代器中长期保留 由于迭代器会提前保存迭代的节点/元素因此即使该节点/元素已从链接阻塞双端队列中被移除也可能无法被GC回收因为迭代器还持有其引用。该问题的关键在于这种保留在时间上是难以预测的即可能是短期、长期、甚至是永久保存。这完全取决于迭代器的迭代频率而频率又与具体的业务相关。频率高就是短期低就是长期不调用就是永久。事实上该问题也是所有弱一致性迭代器的共性是难以被解决的。但所幸的是发生该问题的概率不高并且也只会导致少许对象被延迟回收或浪费少量存储空间因此并不会产生较大的负面影响。 可能导致的频繁老年代GC 由于被移除移除/拿取、内部移除的节点不会断开前驱/后继引用那就可能造成这样一种情况由于移除移除/拿取、内部移除操作的不断执行使得在链接阻塞双端队列外也形成一条条空节点链下文简称外链并最终与队内节点相连接。大致示例如下 上图看起来并无不妥无外乎残留了部分无效节点节点只需等待GC慢慢回收即可。事实上也确实如此Java的GC太过智能以至于我们往往/从来不会考虑垃圾回收的具体过程。实际上虽然无需亲自执行回收但开发者仍有义务保证GC准确高效的执行。在上述所示情况中存在这样一种场景外链中存在部分空节点存活于老年代并与前驱/后继存活于新生代的节点相连造成跨带引用的现象。示例如下 跨带引用是非常难以处理的。在跨带引用中为了回收被引用的新生代对象必须先强制执行老年代对象的回收。老年代的Major GC本身就是不频繁的因为老年代的对象存活周期一般都比较长并且执行速度也远比新生代的Minor GC慢得多有资料说至少有10倍以上的差距因此在实际开发中要时刻注意避免。在当前场景中为了回收外链中处于新生代的空节点必须先触发老年代的Minor GC。这本质上不算太过严重的问题一次跨带引用并不会对程序带来多少影响…但问题的关键在于程序在不断的运行每时每刻都有新的元素被插入/放置同样也不断会有元素被移除移除/拿取、内部移除。这就意味着外链会一次又一次的形成从而频繁的导致跨带引用。 为了解决这一点即在保证迭代器弱一致性的基础上避免跨带引用链接阻塞双端队列采用的方案是将移除/拿取的节点的前驱/后继引用设置为自引用之所以不设置null是因为null是头/尾节点的标志。节点自引用有两大作用一是移除/拿取的节点不再具有其它节点的前驱/后继引用那自然也就不会再出现跨带引用的问题二是其可以作为迭代器的标记位使用。当迭代器迭代是发现节点是自引用时就说明该节点已经因为移除/拿取出队了这就意味着其首个存在于链接阻塞双端队列的前驱/后继节点必然是头/尾节点因此会直接跳跃至链接阻塞双端队列的头/尾部继续进行迭代。 上述操作虽然精妙但遗憾的是该操作并不能对内部移除的节点使用即该类节点依然要保持原本的前驱/后继引用。这是因为该类移除可能在队列的任意位置发生其首个存在于链接阻塞双端队列的前驱/后继节点并不一定位于头/尾部故而不可采用该方案这也意味着内部移除存在着引发跨带引用的隐患…但由于内部移除本身在开发中就较少且不推荐使用…并且想要连续的移除还是有一定难度的…因此总体来说并不会有太大影响。 五 相关系列 《Java ~ Collection【目录】》
http://www.hkea.cn/news/14513814/

相关文章:

  • 山东省住房和城乡建设厅官方网站徐州市网站开发
  • 携程网站联盟首页页面设计模板
  • 怎么样做企业网站安徽网站建设大全
  • 母婴网站建设 社区天津做个网站需要多少钱
  • 自己做网站 有名6融创中国最新消息
  • 网站建设与推广好做吗沈阳网站建设方案推广
  • 教人做美食的网站海淘网站是谁做的
  • 在家做兼职的网站可信赖的深圳网站建设
  • 国内外网站公司简介宣传册设计样本图片
  • app开发网站建设网站建设加班
  • 网站为什么提示风险那个做网站好
  • 安徽万振建设集团网站奇艺广州网站建设熊掌号
  • 做网站卖多少钱一个网站搭建书籍推荐
  • 悠悠我心的个人网站素材linux新建网站
  • seo百度站长工具查询东莞建设局网站
  • 陇西学做网站开发公众号 微网站开发
  • 国内视差网站网站的反链怎么做
  • 石家庄网站推广北京软件开发公司哪家专业
  • vps网站建站助手怎么免费构建自己的网站
  • 做的好的国外网站二维码制作网站链接
  • 绍兴网站建设费用做甲方去哪个网站应聘
  • 百度关键词推广网站江苏永坤建设有限公司网站
  • 国外网站加速商城小程序开发多少钱
  • 泰安企业建站公司平台北京杰诚 做网站
  • 建立网站需要哪些手续遵义网站开发哪家便宜
  • 免费书画网站怎么做的设计网站推荐外网
  • 国内最好用免费建站系统减肥推广
  • 企业网站建设的案例科技网站大全
  • 韶关网站开发广安做网站
  • 免费网站建站方法国外最大的素材网站