[知识整理]Java集合(一) - List
一、实现List的几个类:
ArrayList、LinkedList、CopyOnWriteArrayList、Vector
二、几个List底层的数据结构:
ArrayList - 数组列表
LinkedList - 双链表列表和队列(同时实现List和Queue接口)
Vector - 数组列表(加锁)
CopyOnWriteArrayList - 数组列表(读写分离)
三、List的几种基本操作比较
1、add操作比较
/**
* 比较add操作
* @param minTimes 最小次数
* @param maxTimes 最大次数
* @param stepLen 步长
*/
public static void compareAddMethod(int minTimes, int maxTimes, int stepLen) {
Date begin = null;
Date end = null;
int times = minTimes;
while(times < maxTimes) {
//add: Vector
Vector<Integer> vector = new Vector<Integer>();
begin = new Date();
for(int i=0; i<times; i++) {
vector.add(i);
}
end = new Date();
System.out.println("Vector add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//add: ArrayList
ArrayList<Integer> arrayList = new ArrayList<Integer>();
begin = new Date();
for(int i=0; i<times; i++) {
arrayList.add(i);
}
end = new Date();
System.out.println("ArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//add: LinkedList
LinkedList<Integer> linkedList = new LinkedList<Integer>();
begin = new Date();
for(int i=0; i<times; i++) {
linkedList.add(i);
}
end = new Date();
System.out.println("LinkedList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//add: CopyOnWriteArrayList
if(times<=100000) {
CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
begin = new Date();
for(int i=0; i<times; i++) {
copyOnWriteArrayList.add(i);
}
end = new Date();
System.out.println("CopyOnWriteArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
}
System.out.println("-------------------------------");
times+=stepLen;
}
运算结果:
minTimes = 0, maxTimes = 100000, stepLen = 30000
| times | Vector(ms) | ArrayList(ms) | LinkedList(ms) | CopyOnWriteArrayList(ms) |
| 0 | 0 | 0 | 0 | 0 |
| 30000 | 3 | 2 | 2 | 339 |
| 60000 | 3 | 4 | 1 | 992 |
| 90000 | 1 | 1 | 0 | 2257 |
结果分析:这里可以看出随着增加执行次数的增加CopyOnWriteArrayList所耗时增加较多,这是由于CopyOnWriteArrayList的读写策略造成。CopyOnWriteArrayList进行写操作,先对原底层数组进行复制,然后在复制数组进行写操作,最后复制数组对原数组引进行替换。这里的耗时消耗在复制数组上面,数组元素越多,所消耗的时间就越多。
minTimes = 0, maxTimes = 10000000, stepLen = 1000000
| times | Vector(ms) | ArrayList(ms) | LinkedList(ms) |
| 0 | 0 | 0 | 0 |
| 1000000 | 37 | 20 | 29 |
| 2000000 | 613 | 396 | 603 |
| 3000000 | 80 | 56 | 174 |
| 4000000 | 169 | 27 | 112 |
| 5000000 | 195 | 44 | 91 |
| 6000000 | 235 | 43 | 80 |
| 7000000 | 261 | 56 | 103 |
| 8000000 | 287 | 60 | 226 |
| 9000000 | 362 | 64 | 209 |
结果分析:这里ArrayList的插入比LinkedList快的原因是每次添加元素都是从数组末尾添加,数组直接通过索引在数组末尾添加元素,和LinkedList链表相比省却了寻找节点的时间,若是换成随机添加删除节点的操作,ArrayList就会比LinkedList慢了。而Vector虽然和ArrayList的底层数据结构一样(可变长的数组),但是由于Vector是线程安全的,这导致执行效率会比较慢。
2、remove操作比较
/**
* 比较remove操作
* @param minTimes 最小次数
* @param maxTimes 最大次数
* @param stepLen 步长
*/
public static void compareRemoveMethod(int minTimes, int maxTimes, int stepLen) {
Date begin = null;
Date end = null;
int times = minTimes;
while(times < maxTimes) {
//remove: Vector
Vector<Integer> vector = new Vector<Integer>();
for(int i=0; i<times; i++)
vector.add(i);
begin = new Date();
for(int i=0; i<times; i++)
vector.remove(0);
end = new Date();
System.out.println("Vector remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//remove: ArrayList
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for(int i=0; i<times; i++)
arrayList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
arrayList.remove(0);
end = new Date();
System.out.println("ArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//remove: LinkedList
LinkedList<Integer> linkedList = new LinkedList<Integer>();
for(int i=0; i<times; i++)
linkedList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
linkedList.remove(0);
end = new Date();
System.out.println("LinkedList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//remove: CopyOnWriteArrayList
if(times<=100000) {
CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
for(int i=0; i<times; i++)
copyOnWriteArrayList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
copyOnWriteArrayList.remove(0);
end = new Date();
System.out.println("CopyOnWriteArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
}
System.out.println("-------------------------------");
times+=stepLen;
}
}
运算结果:
minTimes = 0, maxTimes = 100000, stepLen = 30000
| times | Vector(ms) | ArrayList(ms) | LinkedList(ms) | CopyOnWriteArrayList(ms) |
| 0 | 0 | 0 | 0 | 0 |
| 30000 | 90 | 90 | 5 | 229 |
| 60000 | 356 | 351 | 1 | 921 |
| 90000 | 832 | 834 | 0 | 3199 |
结果分析:不出意外,CopyOnWriteArrayList的插入删除操作依旧是耗时最长的。值得注意的是,这里LinkedList的优势体现出来了,删除插入随机节点时链表操作比数组操作是更有效率的。
3、读取操作比较
/**
* 比较读取操作
* @param minTimes 最小次数
* @param maxTimes 最大次数
* @param stepLen 步长
*/
public static void compareReadMethod(int minTimes, int maxTimes, int stepLen) {
Date begin = null;
Date end = null;
int times = minTimes;
while(times < maxTimes) {
//remove: Vector
Vector<Integer> vector = new Vector<Integer>();
for(int i=0; i<times; i++)
vector.add(i);
begin = new Date();
for(int i=0; i<times; i++)
vector.get(i);
end = new Date();
System.out.println("Vector get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//get: ArrayList
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for(int i=0; i<times; i++)
arrayList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
arrayList.get(i);
end = new Date();
System.out.println("ArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
//get: LinkedList
if(times<=100000) {
LinkedList<Integer> linkedList = new LinkedList<Integer>();
for(int i=0; i<times; i++)
linkedList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
linkedList.get(i);
end = new Date();
System.out.println("LinkedList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
}
//get: CopyOnWriteArrayList
CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
for(int i=0; i<times; i++)
copyOnWriteArrayList.add(i);
begin = new Date();
for(int i=0; i<times; i++)
copyOnWriteArrayList.get(i);
end = new Date();
System.out.println("CopyOnWriteArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
System.out.println("-------------------------------");
times+=stepLen;
}
}
运算结果:
minTimes = 0, maxTimes = 100000, stepLen = 30000
| times | Vector(ms) | ArrayList(ms) | LinkedList(ms) | CopyOnWriteArrayList(ms) |
| 0 | 0 | 0 | 0 | 0 |
| 30000 | 2 | 2 | 334 | 0 |
| 60000 | 1 | 1 | 1313 | 0 |
| 90000 | 0 | 0 | 2945 | 0 |
结果分析:这里为什么LinkedList耗时比较长就不需要说明,这里Vector如果在同时频繁写操作的时候读写耗时便会比较长,而由于CopyOnWriteArrayList使用读写分离测的策略(写操作在复制数组中进行,读操作在原数组里面进行)平衡了线程安全和执行性能的矛盾。
四、小结
1、在List元素数量比较少的时候没必要纠结采用哪个List,因为规模小时根本体现不出什么差别,此时要注意是否选取线程安全的List,一般情况是不采取线程安全的List,而是在ArrayList和LinkedList之间选择。
2、Vector - 底层数据结构为可变长数组,数组长度按100%增长,线程安全,写效率低,读效率在多线程环境下也低。
3、ArrayList - 底层数据结构为可变长数组,数组长度按50%增长,线程不安全,随机插入删除操作效率低,随机读取修改元素效率高。
4、LinkedList - 底层数据结构为双向链表,线程不安全,随机插入删除操作效率高,随机读取修改元素效率低。
5、CopyOnWriteArrayList - 底层数据结构为可变长数组,线程安全,写效率低,读效率在多线程环境下也高,但是由于读写分离,读数据可能出现过时的情况(不可重复读)
6、这里CopyOnWriteArrayList读写分离的思想值得我学习。
[知识整理]Java集合(一) - List的更多相关文章
- [知识整理]Java集合
Mark Java集合图
- [知识整理]Java集合(二) - Set
一.实现Set的几个类 HashSet.LinkedHashSet.TreeSet.ConcurrentSkipListSet.CopyOnWriterArraySet 二.对应底层的数据结构 Has ...
- 《Java基础知识》Java集合(Collection)
作为一个Developer,Java集合类是我们在工作中运用最多的.最频繁的类.相比于数组(Array)来说,集合类的长度可变,更加适合于现代开发需求: Java集合就像一个容器,可以存储任何类型的数 ...
- 《Java基础知识》Java集合(Map)
Java集合主要由2大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是2大体系中的顶层接口. 今天主要讲:Map主要有二个子接口,分别为HashMap.Tr ...
- Java基础知识(JAVA集合框架之List与Set)
List和Set概述数组必须存放同一种元素.StringBuffer必须转换成字符串才能使用,如果想拿出单独的一个元素几乎不可能.数据有很多使用对象存,对象有很多,使用集合存. 集合容器因为内部的数据 ...
- 面试知识整理-Java基础
三大特征:封装,继承,多态 多态:简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情. 抽象:抽象是将一类对象的共同特征总结出来构造类的过程 包装,可以讲基本类型当做对象来使用,抽象只关心对 ...
- 学习:java集合
java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE, JavaME, Jav ...
- Java集合--HashMap分析
HashMap在Java开发中有着非常重要的角色地位,每一个Java程序员都应该了解HashMap. 本文主要从源码角度来解析HashMap的设计思路,并且详细地阐述HashMap中的几个概念,并深入 ...
- Java集合框架相关知识整理
1.常见的集合有哪些? Collection接口和Map接口是所有集合框架的父接口 Collection接口的子接口包括:Set接口和List接口 Map接口的实现类主要有:HashMap ...
随机推荐
- petapoco存储过程
db.ExecuteScalar<string>("exec P_GetCode @0,@1,@2,@3,@4,@5",); using (var db = new D ...
- upgrade to ubuntu14.04, ibus input
升级后ibus拼音输入很奇怪,可能和其他输入法产生混淆.解决很简单,只要打开终端输入 ibus-daemon -drx 不用重启或者登出问题便解决.
- 关于Lucene.net 中高亮显示关键词的深究
这几天一直在学习lucene,也写了3篇自己总结的知识点,本以为很容易上手的东西,但是却遇到了一个很棘手的问题,借此,希望可以跟大家探讨一下 问题:使用盘古高亮显示组件后,如搜索“mp3 player ...
- IOS 本地通知推送消息
在现在的移动设备中,好多应用性的APP都用到了推送服务,但是有好多推送的内容,比如有的只是单纯的进行推送一个闹钟类型的,起了提醒作 用,有的则是推送的实质性的内容,这就分为推送的内容来区别用什么推送, ...
- MongoDB中insert方法、update方法、save方法简单对比
MongoDB中insert方法.update方法.save方法简单对比 1.update方法 该方法用于更新数据,是对文档中的数据进行更新,改变则更新,没改变则不变. 2.insert方法 该方法用 ...
- 施耐德Sepam 40系列备自投逻辑
1# 主供: VL1= NOT PVTS_1_3 V1 = VL1 AND P59_1_7 AND P59_1_8 AND P59_1_9VL2 = VL1 AND I12 AND I21 AND I ...
- Struts2环境搭建
1,从http://struts.apache.org 官网下载struts2的源码,最新的源码是2.5版本的,但是考虑到网上2.3版本的教程比较多,所以我下载了一个2.3版本的struts. 2, ...
- 在linux下写一只优雅的爬虫---优雅的获取沈航所有学生的个人信息
一:ubuntu下安装python集成环境pycharm以及免费激活 安装 首先去下载最新的pycharm 2016.2.3,进行安装.可以直接在官网下载.选择自己所对应的版本 PyCharm 的激活 ...
- IT在线学习网站总结
以下是我自己做软件过程中发现的一些不错的IT学习网站,个人感觉比较受用,故总结出来以供IT爱好者一起学习: www.maiziedu.com 麦子学院 www.jikexueyuan.com 极客学 ...
- 关键字sizeof---常年被人误认为函数
sizeof 是关键字不是函数, sample: int i=0; A) sizeof(int); B) sizeof(i); C)sizeof int; D)sizeof i; C) ...