菜鸟教程的图⬆️
总结篇,集合篇源码阅读总结。欢迎讨论留言
目录
基于数组实现的,且没有重新计算索引或者不是实现堆栈的可以做到有序(添加顺序)。
[java基础-集合篇]LinkedBlockingQueue源码解析-优快云博客
[java基础-集合篇]优先队列PriorityQueue结构与源码解析-优快云博客
[java基础-集合篇]LinkedList源码粗析-优快云博客
[java基础-集合篇]有界阻塞队列ArrayBlockingQueue源码解析-优快云博客
1、集合特性
在一般情况,数组的检索比链表快,而链表的插入和删除要比数组快。
1.1、有序特性
添加顺序
基于数组实现的,且没有重新计算索引或者不是实现堆栈的可以做到有序(添加顺序)。
无序=重新计算索引:HashMap(ConcurrentHashMap、HashSet同理)
无序=用于实现堆栈(实现堆栈也会改变索引位置):PriorityQueue
有序=没有对数组索引额外改动的:ArrayList,ArrayBlockingQueue
基于链表实现的,基本有序
有序=特殊有序集合:LinkedHashMap(尽管继承自HashMap,但是通过覆盖newNode方法、Entry类,LinkedHashMap将新元素放到尾部来保障有序。LinkedHashMap底层为基于双向链表结构)
有序=基于链表集合:LinkedList(基于双向链表)、LinkedBlockingQueue(基于单向链表)
特殊有序集合
Treeset、TreeMap、ConcurrentSkipListMap
有序特性-其他顺序
java集合中,一般通过Comparable接口或者Comparator接口来进行大小比较以排序,以PriorityQueue源码为例。
1.2、线程安全
HashTable,ConcurrentHashMap,ArrayBlockingQueue,LinkedBlockingQueue都是线程安全的。
实现方式核心都是通过锁。具体详情等线程篇再写。
2、集合使用场景
考虑读写速度、是否有序、是否需要自定义顺序、线程安全、是否队列形式等。
3、源码细节与代码技巧
3.1、集合中的算法
-
LRU
在LinkedHashMap中,有LRU算法的实现,即LinkedHashMap可以做到移除最近最少使用的数据项。
主要是通过
1、重写removeEldestEntry方法让其返回true
removeEldestEntry方法在put中调用的afterNodeInsertion方法作为if条件使用。可以用作删除最近最少使用的数据项
2、设置accessOrder属性为true
put和get方法,均有使用accessOrder属性作为条件判断的方法——afterNodeAccess方法,将访问过的节点移动到双向链表的尾部。
-
双条件算法
以ArrayBlockingQueue源码为例,使用重入锁+两个Condition条件进行读写并发控制
-
双锁
以LinkedBlockingQueue源码为例,使用一个写重入锁、一个读重入锁+两个Condition条件进行读写并发控制
3.2、代码技巧
1、transient避免序列化
可以看到基于数组实现的结构基本上使用了transient关键词来避免数组的序列化。在一些集合中,实现了自己的writeObject和readObject方法来控制序列化和反序列化的过程。通过这种方式,它可以确保只保存有意义的数据,并且在反序列化时正确地重建队列结构。
2、使用局部变量
源码中大量使用了局部变量,类似final Object[] items = this.items; 而不是直接操作 this.items 。
使用局部变量而不是直接操作类成员变量好处如下:
- 局部变量访问速度更快,类成员变量可能会涉及额外的开销,例如内存屏障或同步。
局部变量通常在栈,而类成员变量在堆,访问局部变量少了堆内存寻址操作,通常快一点。
如果类成员变量是通过同步块或锁保护的,每次访问这些变量时都需要获取和释放锁。这会带来一定的性能开销,尤其是在高并发场景下。将类成员变量赋值给局部变量后,在方法内部使用局部变量可以减少锁的争用,提高程序的执行效率。
- 可以避免意外修改,将修改限于局部
- 表达更清晰
3、String比较
涉及到String比较,先用==比较内存地址,再用equals方法比较值。