Java集合估计是我们开发过程中,用的最多的API了,它位于java.util包下,同时支持多线程的集合类位于java.util.concurrent包下。
我们都知道各种数据结构最底层的组成都是数组或者链表,其实各种集合类也是基于最基本的数据结构进行封装,便于各种场景直接使用。
我们可以把集合想象成一个容器,它可以存储各种对象,扩展和封装了数组和链表,通过算法实现。
有了这些认识,是不是集合也变了没那么抽象了,后续将陆续更新各种常见集合类的底层实现。—慢慢更新
------万变不离其宗,各种集合就像各门各派的招式,但是其本质都是数据结构和算法。
好吧,这是一个不那么合适的比喻。天下武功,唯快不破,透过事物的本质,方能笑傲江湖…扯远了,能不被各路面试官虐惨就心满意足了…
Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue,这4个接口又分别衍生出了很多的实现类。
孙猴子毫毛一吹,子孙千千万?
Collection接口的主要子类关系,如下图所示:
Collection相当于容纳了其他对象的引用,而构成了一个集合的对象,整个集合可以有序的,也可以无序的,它本身不能被直接实现,需要去实现它的子接口如:List,Set。
List接口是一个有序的Collection,能够精准的控制列表中每个元素的插入位置,能够通过索引来访问List中的元素(List中的元素位置,类似数组下标,第一个元素位置为0),允许有相同的元素,且允许null。
常见的实现:ArrayList(查询快)、LinkedList(增删快)。传送门:【Java集合】ArrayList源码解析、【Java集合】LinkedList源码解析。
喂喂,不是还有另外一个儿子Vector吗,对不起,他已经被后浪排在沙滩上了…
Queue接口以队列实现了Collection,队列当然满足一定的队列顺序了,除了优先队列外,都是满足FIFO(先进先出)方式排序元素。Queue实现通常不允许插入null元素,因为null经常被poll方法用做识别队列是否包含元素。
常见的实现:PriorityQueue(优先队列),你期待的传送门还没开启…
Set接口具有和Collection完全一样的接口,只是行为上不同,Set不保存重复元素,且对象是唯一的。
常见的实现:HashSet(由Hash表实现)、LinkedHashSet(由链表和Hash表实现)、TreeSet(有序的Set),你期待的传送门还没开启…
看完Collection:列表,我们再来看看Map:图,以key-value键值对映射关系存储元素。
Map接口的主要子类关系,如下图所示:
将key映射到value的对象,不能包含重复元素,每个key最多映射一个value。
Map实现的类较多:HashMap、HashTable、SortedMap、LinkedHashMap、TreeMap等。你期待的传送门还没开启…
看到这里,应该对Java集合有了整体宏观的认识,你肯定会问:后宫三千,我该选哪个好呢?…醒醒,天亮了
前面讲的集合类好像都是非安全的,那么安全的集合类有哪些呢?
1.CopyOnWriteArrayList:
1)线程安全的List,修改方法(add,set,remove等)都通过集合属性一个ReentrantLock进行同步,先获取锁,才能执行变更操作。但是通过ReentrantLock进行同步只是能保证线程的安全,并不能保持时间上的有序和正确,因为先申请锁然后进入休眠等待的线程,并不一定是最先获取锁的线程,所以,会在时间顺序看,对集合的修改是无序的。
2)对象数组用volatile修饰,其他线程对集合元素数组的修改,能够在其他线程的每次访问都是最新值。
3)在对集合元素数组进行修改时,是先拷贝之前的元素数组出一个新元素数组,在新的元素数组上进行修改,修改完毕后在用元素数组替换旧的元素数组,内存消耗大。
2.ConcurrentSkipListSet:
ConcurrentSkipListSet是实现了NavigableSet接口和继承自AbstractSet的Set集合类,它是线程安全的,内部存储实际是存在ConcurrentNavigableMap中。内部元素的存储是有序的,根据创建ConcurrentSkipListSet时提供的Comparator。
3.CopyOnWriteArraySet:
CopyOnWriteArraySet底层实现是CopyOnWriteArrayList,线程安全的,大部分操作和原理是同CopyOnWriteArrayList。
4.ConcurrentHashMap:
ConcurrentHashMap是线程安全的HashMap,实现了ConcurrentMap接口,所以提供了一些原子性和线程安全的集合操作接口。
JDK1.8之后的ConcurrentHashMap的实现和1.7之前已经大不一样了,保证线程安全的机制从原来的给每个数组segment加锁方式变成了无锁的cas操作,特别是扩容方式被重写了,实现了无锁情况下多线程参与复制旧存储元素到新存储集合上。有一个最重要的不同点就是ConcurrentHashMap不允许key或value为null值。
5.HashTable:
HashTable是线程安全的HashMap,其实就在修改方法上添加synchronized关键字进行同步,同步的粒度太大,性能不佳,不建议使用。
6.ConcurrentSkipListMap:
ConcurrentSkipListMap是基于SkipList存储结构实现的线程安全的有序Map集合,不支持Null为value或者为key,线程安全且有序。
迭代器(Iterator接口)提供了一种方法,来对集合、容器进行遍历的方式,使你能够通过循环来得到换删除集合元素。
ListIterator接口继承于Iterator接口,允许双向遍历列表和修改元素。
比较器(Comparator接口),集合实现Comparator接口,就可以按照你定义的排序方式进行排序。
后续会深入各个集合类的源代码进行分析学习,敬请期待…
【Java集合】ArrayList源码解析
【Java集合】LinkedList源码解析