Java是后端程序员的一门必修课,Java 开发非常方便,针对通用场景的需求, Java 提供了强大的集合框架,大大提高了开发者的生产力。本章透过源码分析了Java集合类之一的LinkedList。
LinkedList
LinkedList 是Java提供的双向链表 ,它不需要像Vector和ArrayList那样调整容量,它也不是线程安全的;如下图2和图3源码;
不同容器类型适合的场景
(1)Vector和ArrayList
Vector和ArrayList作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需要移动后续所有元素。
(2)LinkedList
而LinkedList进行节点插入、删除却要高效得多,但是随机访问性能则要比动态数组慢。所以,在应用开发中,如果事先可以估计到,应用操作是偏向于插入、删除,还是随机访问较多,就可以针对性的进行选择。
LinkedList对操作元素
插入:
LinkedList在插入元素时,须创建一个新的Entry对象,并更新相应元素的前后元素的引用;
查找:
在查找元素时,需遍历链表;
如下图6,图7,图8 ;先检查索引是否符合LinkedList要求;
遍历链表
删除:
在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除即可。
如图按照对象删除源代码:
扩容机制
Vector与ArrayList仅在插入元素时容量扩充机制不一致。对于Vector,默认创建一个大小为10的Object数组,并将capacityIncrement设置为0;当插入元素数组大小不够时,如果capacityIncrement大于0,则将Object数组的大小扩大为现有size+capacityIncrement;如果capacityIncrement<=0,则将Object数组的大小扩大为现有大小的2倍。
效率分析
LinkedList由于基于链表方式存放数据,增加和删除元素的速度较快,但是检索速度较慢。
线程安全问题
LinkedList是非线程安全的,线程安全问题是由多个线程同时写或同时读写同一个资源造成的。
为什么不安全?
简单举例分析启动一个部分,如下图,当多个线程同时对一个LinkedList对象进行添加操作的时候如果线程A执行last = newNode后时间片停止,然后线程B执行last = newNode后时间片也停止。A从新开始执行,其实这个时候B已经改变了LinkedList的结构,但是线程A不知道继续执行,导致A执行后的数据出现错误,随后B执行的数据也会以出现错误。
使用建议:
单线程应尽量使用ArrayList,LinkedList。Vector因为同步会有性能损耗,目前早已经不推荐使用,建议多线程关注线程集合类,如PriorityBlockingQueue,ArrayBlockingQueue
,BlockingDeque等;
Java集合类是如何体现数据结构的?
如下图我们可以看到集合数据结构的体现在共性上,List,Queue
注意细节
Vector和ArrayList作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需要移动后续所有元素。而LinkedList进行节点插入、删除却要高效得多,但是随机访问性能则要比动态数组慢。
很多人盲目的选择LinkedList,因为LinkedList适合插入效率高的场景,但是一定要注意Vector和ArrayList在尾部增删都不会会开辟新内存,效率也是非常高的,如果你的场景是这种情况,用LinkedList反而失去了查询效率。
编译放代码容易乱,所以截取少量图片,大家可以打开编译器自己去看代码,将你的新的总结发布到下发评论和大家一起分享吧。