说明:
以下研究基于JDK 11;
随作者认知理解的变化,本文将持续更新,不保证当前内容的绝对正确;
本文有参考其他文章,在最下方有相关链接。
概述
集合类的功能就是实现各种方式的数据存储,这样一组专门用来存储其它对象的类,一般被称为对象容器类,简称容器类,这组类和接口的设计结构也被统称为集合框架(Collection Framework)。
Java集合框架在 Java.util 包下,实现了常用的基本数据结构,如:集合、线性表、队列、栈、映射表等。
从接口实现的角度它们可以分为Colllection系和Map系,从线程安全与并发的角度它们可以分为非同步集合、同步集合、并发集合。
在Java2之前,java是没有完整的集合框架的,它只有一些简单的可以自扩展的容器类,比如Vector,Stack,Hashtable等。Java Collections Framework(JCF)是通用的容器。
跨语言相关:C++ STL
几个接口
- Collection: 集合层次中的根。一个集合表示一组对象。有些有序,有些无序。有些可重复,有些不可重复。Collection没有直接的实现,而只有它的子接口的对应的实现。子接口主要有List、Set、Queue。
- Set:集合是无序的(LinkedHashSet可以按插入的顺序遍历,但其存储本身是无序的,这里要看怎么理解),没有下标,不可重复。Set的主要实现类有:HashSet、LinkedHashSet、TreeSet、ConcurrentSkipListSet。
- List:列表是有序的,有下标的,可重复的。List的主要实现类是:ArrayList、LinkedList、Vector、CopyOnWriteArrayList。
- Queue:用于多元素有优先级的处理,可以用做FIFO。Queue的主要实现类有:PriorityBlockingQueue、ConcurrentLinkedQueue、ArrayBlockingQueue、LinkedBlockingQueue。
- Deque:用于多元素有优先级的处理,double ended queue,可以用作FIFO,LIFO。Deque的主要实现类有:ArrayDeque、LinkedList、LinkedBlockingDeque、ConcurrentLinkedDeque。
- Map:用于keys到values的映射,keys不能包含重复元素。Map的主要实现类有:IdentityHashMap、HashMap、LinkedHashMap、HashTable。
另外还提供了2个带排序的Set和Map。 - SortedSet:元素升序。
- SortedMap:key升序。
在1.6版本开始,还有两种新的接口NavigableSet、NavigableMap。
A SortedMap/SortedSet extended with navigation methods reporting closest matches for given search targets.
具有了针对给定搜索目标返回最接近匹配项的导航方法,提供诸如:
1 //返回第一个大于e的元素
2 E higher(E e);
之类的“导航性质”的便捷操作。
集合框架图
Collection系集合框架图(不含并发集合).png Map系集合框架图(不含并发集合).png Collection系集合框架图(并发集合).png Map系集合框架图(并发集合).png非同步集合的一些实现类
非同步集合,在并发访问的时候,是非线程安全的,但是由于它们没有同步策略(加锁机制),它们的效率更高。常用的非同步集合它们包括下面几个:
- ArrayList:底层是通过数组实现的。
- LinkedList:底层是通过链表实现的。
- HashSet:底层是通过哈希表实现的。
- LinkedHashSet:是通过链表+哈希表实现的。
- TreeSet:底层是通过树结构实现的。
- PriorityQueue:无界优先级队列。
- ArrayDeque:基于数组的双端队列。
- HashMap:基于哈希表的 Map 接口的实现。
- LinkedHashMap:基于链表+哈希表的Map接口的实现。
- IdentityHashMap:此类使用哈希表实现Map接口,在比较键(和值)时使用引用相等性代替对象相等性。
- EnumMap:Map与枚举类型键一起使用的专用实现,枚举映射在内部表示为数组。
- TreeMap:基于红黑树(Red-Black tree)的 NavigableMap实现。
Java8中对HashMap引入了红黑树,那么相关结构中底层实现应该加上红黑树,本篇不做研究。
同步集合的一些实现类
对每个方法都进行同步加锁,保证线程安全。
- HashTable
- Properties
- Vector
- Stack
- 同步包装器 : [ Collections.synchronizedMap(), Collections.synchronizedList() ]
Java 集合类中非线程安全的集合可以用同步包装器使集合变成线程安全,其实实现原理就是相当于对每个方法多加一层同步锁而已,比如:
HashMap --> Collections.synchronizedMap(new HashMap()) --> Map(SynchronizedMap内部类)
ArrayList --> Collections.synchronizedList(new ArrayList<>()) --> List
并发集合的一些实现类
java.util.concurrent包提供的线程安全类,主要是利用copy-on-write读写优化策略和分段加锁策略,来提高并发性。在大量多线程的场景中选择它们是比较合适的(在线程不多的时候未必能体现时间上的优势)。一些并发容器类如下:
- CopyOnWriteArrayList
- CopyOnWriteArraySet
- ConcurrentSkipListSet
- LinkedBlockingQueue
- PriorityBlockingQueue
- ConcurrentLinkedQueue
- ArrayBlockingDueue
- LinkedBlockingQeque
- CuncurrentLinkedDeque
- ConcurrentHashMap
- ConcurrentSkipListMap
一些总结
集合与数组的区别
数组的长度是固定的,如果想增加长度,只能创建新的数组。
集合的长度是可变的,数据理论可以无限添加,自动扩容。
ArrayList与LinkedList的区别
ArrayList的底层的通过数组实现,所以其随机访问的速度比较快,但是对于需要频繁的增删的情况,效率就比较低了。而对于LinkedList,底层通过链表来实现,所以增删操作比较容易完成,但是对于随机访问的效率比较低。
同步集合类和并发集合类的区别
不管是同步集合还是并发集合他们都支持线程安全,它们之间主要的区别体现在性能和可扩展性,还有它们如何实现的线程安全。
同步集合类,Hashtable 和 Vector 还有同步集合包装类,Collections.synchronizedMap()和Collections.synchronizedList(),相比并发的实现(比如:ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteHashSet)会慢得多。
造成如此慢的主要原因是锁, 同步集合会把整个Map或List锁起来,每个操作都是串行的操作,同一时刻只有一个线程能操作。而并发集合不会,并发集合实现线程安全是通过使用更先进的技术把锁剥离。
比如ConcurrentHashMap 会把整个Map 划分成几个片段,只对相关的几个片段上锁,同时允许多线程访问其他未上锁的片段。
CopyOnWriteArrayList 允许多个线程以非同步的方式读,当有线程写的时候它会将整个List复制一个副本给它。如果在读多写少这种对并发集合有利的条件下使用并发集合,这会比使用同步集合更具有可伸缩性。
本篇完结,如果文章有误,欢迎批评指正!
后续将具体地对相关的类和接口进行研究……
网友评论