集合框架Collections Framework

Java集合

Java集合大致可分为ListSetMap三种体系:

  • List代表有序、重复的集合;
  • Set代表无序、不可重复的集合;
  • Map代表具有映射关系的集合;

主要由CollectionMap两个根接口及其子接口、实现类组成

集合框架Collections Framework

集合框架Collections Framework

集合框架Collections Framework

集合框架Collections Framework

接口

特性

实现类

实现类特性

说明

List

线性、有序的存储容器,

可通过索引访问元素

Vector

线程安全

 不建议使用

ArrayList

基于数组实现,非线程安全

LinkedList

基于链表实现,非线程安全

Set

成员不能重复

HashSet

HashSet类是Set接口的典型实现类

1、不能保证元素的排列顺序,加入的元素要特别注意hashCode()方法的实现

2、HashSet不是同步的,多线程访问同一步HashSet对象时,需要手工同步

3、集合元素值可以是null

元素必须定义hashCode()

LinkedHashSet

LinkedHashSet类也是根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序。与HashSet相比,特点:

1、对集合迭代时,按增加顺序返回元素

2、性能略低于HashSet,因为需要维护元素的插入顺序。但迭代访问元素时会有好性能,因为它采用链表维护内部顺序

元素必须定义hashCode()

TreeSet

保持次序的Set,底层为树结构

元素必须实现Comparable接口

EnumSet

EnumSet类是专为枚举类设计的集合类

元素必须是指定枚举类型的枚举值

Map

保存键值对成员

Hashtable

线程安全

 不建议使用

HashMap

可以使用null作为key和value,非线程安全

任意Object对象,如果修改了equals方法,需同时修改hashCode方法

TreeMap

默认根据自然顺序进行排序,或者根据创建映射时提供的Comparator进行排序。TreeMap不允许null作为key。

键成员要求实现Comparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。

LinkedHashMap

LinkedHashMap从HashMap类继承而来。以链表来维护内部顺序。很多方面跟LinkedHashSet类似。LinkedHashMap它可以记住key-value对的添加时的顺序, 同时避免使用TreeMap时性能受到的影响。

与HashMap相同

IdentityHashMap

与HashMap的不同在于,只有两个key严格相等(key1 == key2)时,IdentityHashMap才认为两个key相等;而对于普通HashMap而言,只要key1.equals(key2)且hashCode相同即可。同样允许null值,不能保证顺序。

成员通过==判断是否相等

WeakHashMap

弱键映射,允许GC回收所指向的对象。

EnumMap

EnumMap是一个与枚举类一起使用的Map实现。它的key必须是单个枚举类的枚举值。EnumMap不允许使用null作为key,但可作为value。

 

工具类:

  • Arrays 此类包含用来操作数组(比如排序和搜索)的各种方法。两个工具类 Arrays 和 Collections
  • Collections 主要提供了在 collection 上进行操作的静态方法(同步集合类方法) 。

ConcurrentCollection

JDK1.5版本中,加入java.uill.concurrent包,其中包含集合的线程安全方式的实现。

集合框架Collections Framework 集合框架Collections Framework

接口

特性

实现类

实现类特性

说明

List

线性、有序的存储容器,

可通过索引访问元素

CopyOnWriteArrayList

CopyOnWriteArrayList是concurrent包中提供的一个非阻塞型的,线程安全的List实现。其中所有可变操作(添加、设置,等等)都是通过对基础数组进行一次新的复制来实现的。

CopyOnWriteArrayList在进行数据修改时,都不会对数据进行锁定,每次修改时,先拷贝整个数组,然后修改其中的一些元素,完成上述操作后,替换整个数组的指针。

对CopyOnWriteArrayList进行读取时,也不进行数据锁定,直接返回需要查询的数据,如果需要返回整个数组,那么会将整个数组拷贝一份,再返回,保证内部array在任何情况下都是只读的。

CopyOnWriteArrayList在少量修改,频繁读取的场景下,有很好的并发性能。

Set

成员不能重复

CopyOnWriteArraySet

它最适合于 set 大小通常保持很小、只读操作远多于可变操作以及需要在遍历期间防止线程间冲突的应用程序。

它是线程安全的。

因为通常需要复制整个基础数组,所以可变操作(添加、设置、移除,等等)的开销巨大。

迭代器不支持可变移除操作。

使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。

元素必须定义hashCode()

Map

保存键值对成员

ConcurrentHashMap

ConcurrentHashMap是一个线程安全的哈希表,它的主要功能是提供了一组和HashMap功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁。

Queue

 

如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作。

  • BlockingQueue 不接受 null 元素。
  • BlockingQueue 可以是限定容量的。
  • BlockingQueue 实现主要用于生产者-使用者队列。
  • BlockingQueue 实现是线程安全的。

BlockingQueue常用方法:

  • boolean add(E o): 将指定的元素添加到此队列中(如果立即可行),在成功时返回 true,其他情况则抛出 IllegalStateException。
  • boolean offer(E o): 如果可能的话,将指定元素插入此队列中。成功返回true,否则返回false。
  • void put(E o): 将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)
  • E poll(long timeout, TimeUnit unit): 检索并移除此队列的头部,如果此队列中没有任何元素,则等待指定等待的时间(如果有必要)。
  • E take(): 检索并移除此队列的头部,如果此队列不存在任何元素,则一直等待。
 ArrayBlockingQueue  

一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。

这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。

此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。

 
LinkedBlockingQueue

一个基于已链接节点的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。

可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。如果未指定容量,则它等于 Integer.MAX_VALUE。除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。

 
DelayQueue Delayed 元素的一个*阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满。此队列不允许使用 null 元素。
DelayQueue使用场景较少,常见的例子比如使用一个DelayQueue来管理一个超时未响应的连接队列。
 
PriorityBlockingQueue 一个*的阻塞队列,它使用与类 PriorityQueue 相同的顺序规则:基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定),并且提供了阻塞检索的操作。虽然此队列逻辑上是*的,但是由于资源被耗尽,所以试图执行添加操作可能会失败(导致 OutOfMemoryError)。此类不允许使用 null 元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象(因为这样做会抛出 ClassCastException)。  
SynchronousQueue

一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要取得元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)添加元素;也不能迭代队列,因为其中没有元素可用于迭代。队列的头 是尝试添加到队列中的首个已排队线程元素;如果没有已排队线程,则不添加元素并且头为 null。对于其他 Collection 方法(例如 contains),SynchronousQueue 作为一个空集合。此队列不允许 null 元素。

同步队列类似于 CSP 和 Ada 中使用的 rendezvous 信道。它非常适合于传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另一个线程中运行的对象,它就必须与该对象同步。

对于正在等待的生产者和使用者线程而言,此类支持可选的公平排序策略。默认情况下不保证这种排序。但是,使用公平设置为 true 所构造的队列可保证线程以 FIFO 的顺序进行访问。公平通常会降低吞吐量,但是可以减小可变性并避免得不到服务。