java集合总结

List

ArrayList

  1. 以数组实现,有容量限制,超出限制时会自动扩充容量,为避免不必要的复制操作,使用时尽量给出数组的预估大小。
  2. 按数组小标随机访问(get(i)/set(i,e))的性能很高,删除元素性能低,适合数据比较固定,随机访问操作远多于删除操作的列表

LinkedList

  1. 以双向链表实现,无容量限制,但双向链表本身使用了更多空间
  2. 按下标访问元素,需要遍历链表移动指针
  3. 插入删除元素的效率高,因为只需要修改操作节点的前后节点指针

CopyOnWriteArrayList

  1. 实现并发的ArrayList,使用CopyOnWrite策略,在修改时先复制一个快照来修改,改完后再让内部指针指向新数组,因为对快照的操作对读操作不可见,所以只有写锁没有读锁,比较适合读多写少的场景。如果更新频率较高,或数组较大时,还是Collections.synchronizedList(list),对所有操作用同一把锁来保证线程安全更好。
  2. 增加了addIfAbsent(e)方法,会遍历数组来检查元素是否已存在,性能不太好

Map

HashMap

  1. 以Entry[]数组实现的哈希桶数组,用key的哈希值取模桶数组的大小可得到数组下标。
  2. 插入元素时,如果两个key落在同一个桶,Entry用一个next属性实现多个Entry以单向链表方式存放,后入桶的Entry将next指向桶当前的Entry。查找哈希值为17的key时,先定位到第一个哈希桶,然后以链表遍历所有元素,逐个比较其key值
  3. 当Entry数量达到桶数量的75%时,会成倍扩容桶数组,并重新分配所有原来Entry。
  4. 在JDK8里,新增默认为8的閥值,当一个桶里的Entry超过8个,就不以单向链表而以红黑树来存放以加快查找速度。

LinkedHashMap

  1. 扩展HashMap增加双向链表实现,支持iterator()时按Entry的插入顺序来排序(只算插入不算更新, 如果设置accessOrder属性为true,则所有读写访问都算)
  2. 实现上是在Entry上再增加属性before/after指针,插入时把自己加到Header Entry的前面去。如果所有读写访问都要排序,还要把前后Entry的before/after拼接起来以在链表中删除掉自己。

TreeMap

  1. 以红黑树实现,支持iterator()时按Key值排序,可按实现了Comparable接口的Key的自然顺序升序排序,或由传入的Comparator控制。可想象的,在树上插入/删除元素的代价一定比HashMap的大。
  2. 支持SortedMap接口,如firstKey(),lastKey()取得最大最小的key,或sub(fromKey, toKey), tailMap(fromKey)剪取Map的某一段。

ConcurrentHashMap

  1. 并发优化的HashMap,默认16把写锁(可以设置更多),有效分散了阻塞的概率,而且没有读锁
  2. 数据结构为Segment[],Segment里面才是哈希桶数组,每个Segment一把锁。Key先算出它在哪个Segment里,再算出它在哪个哈希桶里。
  3. 支持ConcurrentMap接口,如putIfAbsent(key,value)与相反的replace(key,value)与以及实现CAS的replace(key, oldValue, newValue)。
  4. 没有读锁是因为put/remove动作是个原子动作(比如put是一个对数组元素/Entry 指针的赋值操作),因此read不会看到一个更新动作的中间状态。

ConcurrentSkipListMap

JDK6新增的并发优化的SortedMap,以SkipList实现。SkipList是红黑树的一种简化替代方案,是个很流行的有序集合算法,见入门教程。Concurrent包选用它是因为它支持基于CAS的无锁算法,而红黑树则没有好的无锁算法。
很特殊的,它的size()不能随便调,会遍历来统计。

Set

(Set几乎都是内部用一个Map来实现, 因为Map里的KeySet就是一个Set,而value全部使用同一个Object。Set的特征也继承了那些内部Map实现的特征。)

  1. HashSet:内部是HashMap。
  2. LinkedHashSet:内部是LinkedHashMap。
  3. TreeSet:内部是TreeMap的SortedSet。
  4. ConcurrentSkipListSet:内部是ConcurrentSkipListMap的并发优化的SortedSet。
  5. CopyOnWriteArraySet:内部是CopyOnWriteArrayList的并发优化的Set,利用其addIfAbsent()方法实现元素去重,如前所述该方法的性能很一般。

Queue

Queue是在两端出入的List,所以也可以用数组或链表来实现。

LinkedList

是的,以双向链表实现的LinkedList既是List,也是Queue。它是唯一一个允许放入null的Queue。

ArrayDeque

  1. 以循环数组实现的双向Queue。大小是2的倍数,默认是16。
  2. 普通数组只能快速在末尾添加元素,为了支持FIFO,从数组头快速取出元素,就需要使用循环数组:有队头队尾两个下标:弹出元素时,队头下标递增;加入元素时,如果已到数组空间的末尾,则将元素循环赋值到数组[0],同时队尾下标指向0,再插入下一个元素则赋值到数组[1],队尾下标指向1。如果队尾的下标追上队头,说明数组所有空间已用完,进行双倍的数组扩容。

线程安全的队列

  1. ConcurrentLinkedQueue/ConcurrentLinkedDeque
    无界的并发优化的Queue,基于链表,实现了依赖于CAS的无锁算法
  2. PriorityBlockingQueue
    无界的并发优化的PriorityQueue,也是基于二分堆。使用一把公共的读写锁。虽然实现了BlockingQueue接口,其实没有任何阻塞队列的特征,空间不够时会自动扩容。
  3. DelayQueue
    内部包含一个PriorityQueue,同样是无界的。元素需实现Delayed接口,每次调用时需返回当前离触发时间还有多久,小于0表示该触发了。
    pull()时会用peek()查看队头的元素,检查是否到达触发时间。ScheduledThreadPoolExecutor用了类似的结构。

线程安全的阻塞队列

  1. BlockingQueue的队列长度受限,用以保证生产者与消费者的速度不会相差太远,避免内存耗尽。队列长度设定后不可改变。当入队时队列已满,或出队时队列已空,不同函数的效果见下表:
可能报异常 返回布尔值 可能阻塞等待 可设定等待时间
入队 add(e) offer(e) put(e) offer(e, timeout, unit)
出队 remove() poll() take() poll(timeout, unit)
查看 element() peek()
  1. ArrayBlockingQueue
    定长的并发优化的BlockingQueue,基于循环数组实现。也由一把公共读写锁与notFull、notEmpty两个Condition管理阻塞状态。
  2. LinkedBlockingQueue
    可选定长的并发优化的BlockingQueue,基于链表实现,所以可以把长度设为Integer.MAX_VALUE。有takeLock、putLock两把锁及notFull、notEmpty两个Condition精细复杂的管理阻塞状态。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容