常用结构

ArrayDeque

特点:

是一个双端队列。发音与“ArrayDeck”相同

既可以作为Stack(Last-In-First-Out, LIFO)

也可以作为Queue(First-In-First-Out,FIFO)

它的方法中,基本上都有两套实现,

  • 一种在操作失败时抛出异常;
  • 一种是返回状态或者值。

是非线程安全的

不接受Null

工作速度明显比Stack快(faster than the synchronized Stack)

  • Jdk原生的Stack是使用synchronize来实现的

由于更好的引用局部性,是比 LinkedList 更快的队列

ArrayDeque 返回的迭代器是快速失败的(fail-fast)

添加元素时,当头尾指针相遇时,ArrayDeque 自动将数组的大小加倍 ???

底层原理:

底层是Array(数组),初始化的大小为16,维护了两个指针,即head和tail(头和尾)。

ArrayDeque提供的基础API

每个操作都提供了两种选择

The first group consists of methods that throw exception if the operation fails. The other group returns a status or a value:

Operation Method Method throwing Exception
Insertion from Head offerFirst(e) addFirst(e)
Removal from Head pollFirst() removeFirst()
Retrieval from Head peekFirst() getFirst()
Insertion from Tail offerLast(e) addLast(e)
Removal from Tail pollLast() removeLast()
Retrieval from Tail peekLast() getLast()

注: offerFirst()与offerLast()方法中分别对应调用了addFirst()与addLast()方法,所以当传递参数为Null时,offerFirst()与offerLast()也会像addFirst()和addLast()一样抛出NPE的报错。

以上内容参考:Introduction to the Java ArrayDeque | Baeldung

什么是fail-fast,fail-safe机制?

fail-fast机制是Java集合(Collection)中的一种错误机制。

在用Iterator(迭代器)遍历一个集合对象时,如果遍历过程中集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception(并发修改异常)

主要目的是尽可能保证数据的一致性。防止在遍历的时候进行修改导致集合前后数据不一致。

使用增强for循环遍历集合和用迭代器实质是一样的。

forEach版本的for循环,其字节码与iterator一样。

阿里巴巴Java开发手册中要求,不要在foreach循环中进行元素的remove/add操作。如果有remove的需要,请使用iterator方式,调用iterator中的remove方法。如果并发操作,需要对iterator对象加锁。

理由:

  1. iterator的next()方法中会对modCount与expectedModCount这两个参数判断是否相等,不相等就抛异常。
  2. iterator的remove()方法会复位expectedModCount为modCount使这两个参数相等;
  3. ArrayList中的add()与remove()两个方法只修改了modCount参数,所以当进行next()调用时判断参数相等时就抛出异常了。

注意:代码中,我们不能对Arrays.asList()生成的ArrayList对象进行增删操作,因为asList()生成的ArrayList并没有重写add()和remove()方法,会直接抛出UnsupportedOperationException异常。

fail-safe

是对原数据copy之后,对新数据修改的操作。

在一些场景中,我们想避免fail-fast机制抛出的异常,这时我们可以将ArrayList替换为fail-safe机制的CopyOnWriteArrayList。

典型的实现是,CopyOnWriteArrayList

写时复制,简单理解就是,当我们向一个容器中添加元素时,先将当前容器复制出一个,然后向新的容器中添加元素,添加完元素之后,再将原容器的引用指向新的容器。

优点很多,这里举一个重要的点:

优点一:可以对CopyOnWriter容器进行并发读,而不需要加锁。因为当前容器不会增删任何元素。添加元素的时候需要加锁。

是一种读写分离的思想,读和写是不同的容器。

缺点 :占用内存问题和数据一致性问题。

  • 占用内存问题:因为复制了一份,所以新加对象时会比较占内存;

  • 数据一致性问题:因为读写分离,所以只能保证数据最终的一致性,不能保证实时的一致性。如果希望写入的数据马上能读到,那么不能使用CopyOnWrite容器。

适用场景:用于读多写少的并发场景,比如白名单,黑名单,商品类目的访问和更新场景。

以上内容参考:一文彻底弄懂fail-fast、fail-safe机制(带你撸源码) (juejin.cn)

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信