皆非的万事屋

Java容器知识总结

本文内容整理自JavaGuide

集合概述

Java 集合概览

Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 Collecton接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:ListSetQueue

四者区别

集合框架底层数据结构总结

Map

List

Set

Queue

(Queue是单端队列,Deque 是双端队列,Deque 还提供有 push() 和 pop() 等其他方法,可用于模拟栈。)

如何选用

对于Map:需要排序时选择 TreeMap, 不需要排序时就选择 HashMap, 需要保证线程安全就选用 ConcurrentHashMap,需要记录插入顺序就用LinkedHashMap.

RandomAccess 接口

ArrayList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能。 RandomAccess 接口只是标识,并不是说 ArrayList 实现 RandomAccess 接口才具有快速随机访问功能的

PriorityQueue

优先队列

对比

ArrayDeque 与 LinkedList

HashMap 和 Hashtable

HashMap 和 TreeMap

ConcurrentHashMap 和 Hashtable

两个都是线程安全的:

HashSet 如何检查重复

HashMap

put()过程:

HashMap 的长度为什么是 2 的幂次方

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀

HashMap 多线程操作导致死循环问题

1.7主要原因在于并发下的 Rehash (扩容操作)会造成元素之间会形成一个循环链表,同时会造成数据丢失的情况。
(JDK1.7的扩容操作,重新定位每个桶的下标,并采用头插法将元素迁移到新数组中。头插法会将链表的顺序翻转,这也是形成死循环的关键点)

不过jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下推荐使用 ConcurrentHashMap 。

总结

遍历方式

entrySet 的性能比 keySet 的性能高出了一倍之多,因此我们应该尽量使用 entrySet 来实现 Map 集合的遍历。

使用注意

Collections.synchronizedList

SynchronizedList 就是在 List的操作外包加了一层synchronize同步控制。

List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized (list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

Iterator<E> iterator();这个方法没有加锁,不是线程安全的,所以如果要遍历,还是必须要在外面加一层锁。

使用Iterator迭代器的话,似乎也没必要用Collections.synchronizedList的方法来包装了——反正都是必须要使用Synchronized代码块包起来的。

所以总的来说,Collections.synchronizedList这种做法,适合不需要使用Iterator、对性能要求也不高的情况。

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »