博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图学java基础篇之集合
阅读量:6277 次
发布时间:2019-06-22

本文共 3720 字,大约阅读时间需要 12 分钟。

hot3.png

(本文部分图片引用自其他博客,最后有链接,侵删。由于笔记使用markdown记录,格式可能不是太好看,见谅)

集合结构

红字为java.util包下的,绿字为concurrent包下扩展的与并发相关的类

List

ArrayList

功能:有序非线程安全列表

要点:

  • 底层存储用Object数组
  • 元素可为null
  • 自动扩容至1.5倍
  • 适合随机访问,不适合大量或频繁增删
LinkedList

功能:有序非线程安全列表

要点:

  • 基于双向链表实现
  • 元素可为null
  • 同时实现了双端队列Deque,支持队列、堆栈操作
  • 适合增删,顺序访问,不适合随机访问
Vector

功能:有序线程安全列表

要点:

  • 功能和ArrayList一样,只有线程安全区别,效率较ArrayList低
  • 实际上算是老版本的List,除了线程安全的情况下不用
Stack

功能:基于Vector实现的堆栈

要点:

  • 线程安全
  • 后进先出(LIFO)1
CopyOnWriteArrayList

功能:快照版本的ArrayList,修改操作通过复制一份数组操作

要点:

  • 线程安全
  • 任何修改都会在拷贝的新副本上进行
  • 修改操作通过ReentrantLock同步
  • 迭代器只能访问,不能修改,且不会因为遍历过程中修改而抛异常
实现线程安全List的方法
  • 使用synchronized:对List操作是进行同步,需要自己控制
  • 使用Vector:效率低,已经较少使用了
  • 使用CopyOnWriteArrayList,前边已经介绍了,这个只能在量小读多写少的场景下用,且性能很差,一般不要用
  • 使用Collections.synchronizedList():工具类提供的一个比较简便的方法,可以直接创建一个线程安全的list,建议使用。其原理是对ArrayList进行包装,通过一个对象锁来控制并发,需要注意的是要弄清楚对象锁锁的是哪个对象。

Map

HashMap

功能:

要点:key-value的map,存储位置根据key的hash值确定

  • 非线程安全
  • 底层使用Entry<K, V>数组table
  • 冲突使用链存储
  • table长度为2^n,这样结合hash算法有利于均匀分布
  • 当发生冲突时,新元素会插入到链首
  • 每次table容量变化时,需要重新rehash
  • 键值均可为null
HashTable

功能:key-value的map,存储位置根据key的hash值确定,与Hash的算法不同之处是,其位置直接通过hash(key)%table.length计算(HashMap使用h&(length – 1)计算,效率更高,才外还有一些细节不同,可自行参看源码)

要点:

  • 线程安全
  • 继承自Dictionary
  • 底层使用Entry<K, V>数组table
  • 冲突使用链存储
  • table长度为2^n,这样结合hash算法有利于均匀分布
  • 当发生冲突时,新元素会插入到链首
  • 每次table容量变化时,需要重新rehash
  • 键值不能为空
TreeMap

功能:基于实现的有序集合 要点:

  • 非线程安全
  • 底层为一个棵红黑树
  • 继承NavigableMap,主要实现了SortMap,因此是有序的
  • 增删改查都可参考红黑树操作
ConcurrentHashMap

功能:线程安全的HashMap,属于java.util.concurrent下的拓展类

要点:

  • 线程安全
  • 底层实现是一个Segment<K, V>数组,Segment内部通过一个HashEntry<K, V>数组存储元素数据,同时Segment继承了,直接通过本身的锁对改段数据操作同步
  • 从底层结构可以发现,其修改时不会对整个集合加锁,而是对段加锁,因此允许同时修改多个段,效率更高
  • 继承NavigableMap,主要实现了SortMap,因此是有序的
  • Segment的划分是通过key的hashCode计算
ConcurrentSkipListMap

功能:线程安全的有序Map,是通过一个叫做的数据结构实现 要点:

  • 线程安全
  • 底层实现是一个多层链表,每层元素都有序,每低一层都包含上一层的元素,最底层包含所有元素。这样设计的巧妙之处是从上层逐层查找时,能够快速定位元素区间。思想上有点像折半查找,不过是把每次折半的中间值分层存了起来。同时链表结构是修改操作同样高效
  • key是有序的
  • 空间换时间,效率很高,但是空间占用也很厉害
Map的用法
  • 非线程安全情景基本上都用HashMap
  • 有序用TreeMap
  • 线程安全优先ConcurrentHashMap
  • ConcurrentHashMap和ConcurrentSkipListMap的优劣主要在于并发量,并发量不高时前者效率高,并发量很大时可以考虑后者

Set

HashSet

功能: 就是一个value均为同一个PRESENT对象的HashMap 要点:

  • 非线程安全
  • 底层为一个HashMap,其所有元素value值是一个Object类型的静态常量
  • 其他参考HashMap
TreeSet

功能: 同TreeMap 要点:

  • 非线程安全
  • 底层为一个TreeMap,其所有元素value值是一个Object类型的静态常量
  • 其他参考TreeMap
ConcurrentSkipListSet

功能: 同ConcurrentSkipListMap

CopyOnWriteArraySet

功能: 同ConcurrentSkipListMap

要点:

  • 需要注意的是底层实现是通过CopyOnWriteArrayList,而非HashMap
  • 使用场景与CopyOnWriteArrayList一样

Queue

Queue实现了队列操作,是基本集合的一个扩充,特点是提供了队列操作offer、poll和peek,主要分为两类,一类只支持单端操作,常见的如PriorityQueue,另一类为双端队列,可实现堆栈操作,均实现Deque。需注意的是队列也提供了add和remove,但应避免使用。

PriorityQueue

功能:如其名,优先级队列,可根据Comparator实现优先级排列

要点:

  • 非线程安全
  • 底层为一个Object数组
  • 不提供Comparator时按照元素自然顺序
ArrayDeque

功能:如其名,优先级队列,可根据Comparator实现优先级排列

要点:

  • 非线程安全
  • 底层为一个E[]数组,同时提供head和tail记录存储数据的首位位置
  • 由于使用数组不是链表,速度比LinkedList更快
LinkedBlockingDeque

功能:阻塞队列,支持支持FIFO和FILO

要点:

  • 线程安全
  • 底层为一个链表,通过一个ReentrantLock锁控制并发
  • 可指定容量,实现阻塞,队满时插入阻塞,队空时读取阻塞,不指定则取最大整数
  • 注意take在空时不阻塞直接返回失败,而poll则会阻塞
  • 可指定元素超时时间
LinkedBlockingQueue

功能:阻塞队列,和LinkedBlockingDeque基本一样,不过支持队列操作

PriorityBlockingQueue

功能:优先级阻塞队列,直接看名字,不解释了

SynchronousQueue

功能:阻塞队列,特殊之处在于其不存储元素,一个元素入队之后必须出队,否则阻塞,可以理解为1个元素的阻塞队列

LinkedTransferQueue

功能:LinkedBlockingQueue和SynchronousQueue的结合体,特点是如果一个元素入队过程中发现又出队请求,则直接返回,不会再插入链表中 要点:

  • 注意其并发并非通过ReentrantLock,而是通过工具类实现
DelayQueue

功能:延迟队列,只有达到指定时间的元素才能出队

要点:

  • 底层实现是一个PriorityQueue,通过ReentrantLock控制并发
  • 可以理解为一个以入队时间-延迟时间为优先级的队列

一些使用上的浅见

  • 从上边的总结可以看出来java对于集合的实现非常完善,几乎所有场景都有对应的类。因此我们应该避免重复造轮子,在合适的场景下使用合适的集合不仅省力,而且更可靠
  • 能简则不繁,其实多数情况下我们使用基本的几个类就够了,复杂的实现一般用于底层框架_(如JDK以及一些常用框架中就用到了不少并发的实现,但其场景都十分鲜明)_。如果平时写也想上层逻辑时使用了负责的集合类,往往我们需要认真考虑下真的有没有必要,或者这部分是不是可以抽象为一个通用的组件,这算是个很有用的代码架构技巧吧。
  • 无论怎么用,理解至上。几个基本类之所以用的顺手是因为我们熟悉其特性,而对于复杂的集合类一定要理解其特性,否则很容易踩坑。集合部分算是JDK中最容易理解的代码了,花一会儿时间而保证优质代码还是很值的。

备注

一些参考博客 (都是很优秀的博客,若个人看源码吃力,可以参考着这些博客来看)

以上xmind图源文件以及该系列相关文件都将同步至,敬请关注

转载于:https://my.oschina.net/goodtemper/blog/521649

你可能感兴趣的文章
第十三章 RememberMe——《跟我学Shiro》
查看>>
mysql 时间函数 时间戳转为日期
查看>>
索引失效 ORA-01502
查看>>
Oracle取月份,不带前面的0
查看>>
Linux Network Device Name issue
查看>>
IP地址的划分实例解答
查看>>
如何查看Linux命令源码
查看>>
运维基础命令
查看>>
Linux下的lds链接脚本简介(二)
查看>>
入门到进阶React
查看>>
C++每日练笔之日期类(基类)
查看>>
SVN 命令笔记
查看>>
修复Postfix 的Relay access denied问题
查看>>
检验手机号码
查看>>
重叠(Overlapped)IO模型
查看>>
ffmpeg study 1
查看>>
Git使用教程
查看>>
使用shell脚本自动监控后台进程,并能自动重启
查看>>
Flex&Bison手册
查看>>
MySQL 5.6 for Windows 解压缩版配置安装
查看>>