ArrayList、LinkedList、Vector、Array
ArrayList 本质是一个数组。
优势:追加元素到数组末尾的时候速度快,同时检索元素的速度也快。
劣势:如果要插入一个元素到数组之间慢;如果要追加的元素数量多于数组的容量,则需要频繁扩容使用Arrays.Arrays.copyOf 重新创建一个合适容量的数组
LinkedList 本质是一个list
优势:追加元素没有容量限制,追加速度快,无论是追加元素到链表哪个位置
劣势:检索元素慢
测试代码如下:
package com.drafire.testall.Sevice; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.Random; @SpringBootTest @RunWith(SpringRunner.class) public class ListClass { private final ArrayList arrayList = new ArrayList(); private final LinkedList linkedList = new LinkedList(); //初始化容量 private static int INITIAL_SIZE = 10000000; //累计插入元素的次数 private static int ADD_SIZE = 1000; //插入的元素 private static int ADD_NUM = 3; //插入元素的位置 private static int ADD_INDEX = 988; //线程数量 private static final int THREAD_SIZE = 10; //修改元素的位置 private final int CHANGE_INDEX = 5; //测试线程安全 @Test public void testThreadSafe() { init(); testArrayListThreadSafe(); testLinkedListThreadSafe(); } //测试性能 @Test public void testNature() { setArrayList(); setLinkedList(); testAddArrayList(); testAddLinkList(); testQueryArrayListItem(); testQueryLinkedListItem(); } private void init() { for (int i = 0; i < THREAD_SIZE; i++) { arrayList.add(i, THREAD_SIZE + i); linkedList.add(i, THREAD_SIZE + i); } } private void testArrayListThreadSafe() { MyArrayListThread[] myArrayListThreads = new MyArrayListThread[THREAD_SIZE]; for (int i = 0; i < THREAD_SIZE; i++) { myArrayListThreads[i] = new MyArrayListThread(i); } for (int i = 0; i < THREAD_SIZE; i++) { Thread thread = new Thread(myArrayListThreads[i]); thread.start(); } System.out.println("arrayList[" + CHANGE_INDEX + "]=" + arrayList.get(CHANGE_INDEX)); } private void testLinkedListThreadSafe() { MyLinkedListThread[] myLinkedListThreads = new MyLinkedListThread[THREAD_SIZE]; for (int i = 0; i < THREAD_SIZE; i++) { myLinkedListThreads[i] = new MyLinkedListThread(i); } for (int i = 0; i < THREAD_SIZE; i++) { //不要调用run方法。因为run()实际上只是跑了主进程一个线程 Thread thread = new Thread(myLinkedListThreads[i]); thread.start(); } System.out.println("linkedList[" + CHANGE_INDEX + "]=" + linkedList.get(CHANGE_INDEX)); } private void setArrayList() { Date st = new Date(); for (int i = 0; i < INITIAL_SIZE; i++) { arrayList.add(i); } Date et = new Date(); System.out.println("arrayList 初始化使用时间:" + (et.getTime() - st.getTime())); } private void setLinkedList() { Date st = new Date(); for (int i = 0; i < INITIAL_SIZE; i++) { linkedList.add(i); } Date et = new Date(); System.out.println("linkedList 初始化使用时间:" + (et.getTime() - st.getTime())); } private void testAddArrayList() { //ArrayList 本质是一个数组。集合的优势在于,追加元素到数组末尾的时候速度快,同时检索元素的速度也快。 // 但是如果要插入一个元素到数组之间,就慢;另外,如果要追加的元素数量多于数组的容量,则需要频繁扩容 //使用Arrays.Arrays.copyOf 重新创建一个合适容量的数组 Date st = new Date(); for (int i = 0; i < ADD_SIZE; i++) { arrayList.add(ADD_INDEX, ADD_NUM); } Date et = new Date(); System.out.println("arrayList在" + ADD_INDEX + "处添加元素:" + ADD_NUM + "," + ADD_SIZE + "次,使用时间:" + (et.getTime() - st.getTime())); } private void testAddLinkList() { //LinkedList本质是一个链表。list的优势在于,没有容量的概念,追加元素速度快 Date st = new Date(); for (int i = 0; i < ADD_SIZE; i++) { linkedList.add(ADD_INDEX, ADD_NUM); } Date et = new Date(); System.out.println("linkedList在" + ADD_INDEX + "处添加元素:" + ADD_NUM + "," + ADD_SIZE + "次,使用时间:" + (et.getTime() - st.getTime())); } private void testQueryArrayListItem() { Date st = new Date(); for (int i = 0; i < ADD_SIZE; i++) { arrayList.get(new Random().nextInt(INITIAL_SIZE)); } Date et = new Date(); System.out.println("arrayList随机检索元素:" + ADD_SIZE + "次,使用时间:" + (et.getTime() - st.getTime())); } private void testQueryLinkedListItem() { Date st = new Date(); for (int i = 0; i < ADD_SIZE; i++) { linkedList.get(new Random().nextInt(INITIAL_SIZE)); } Date et = new Date(); System.out.println("linkedList随机检索元素:" + ADD_SIZE + "次,使用时间:" + (et.getTime() - st.getTime())); } private class MyArrayListThread implements Runnable { private int value; public MyArrayListThread(int v) { this.value = v; } @Override public void run() { arrayList.set(CHANGE_INDEX, value); } } private class MyLinkedListThread implements Runnable { private int value; public MyLinkedListThread(int v) { this.value = v; } @Override public void run() { linkedList.set(CHANGE_INDEX, value); } } }
调用testNature(),结果如下:
arrayList 初始化使用时间:4290
linkedList 初始化使用时间:1676
arrayList在988处添加元素:3,1000次,使用时间:6037
linkedList在988处添加元素:3,1000次,使用时间:5
arrayList随机检索元素:1000次,使用时间:7
linkedList随机检索元素:1000次,使用时间:34017
调用testThreadSafe(),结果如下:
arrayList[5]=9
linkedList[5]=8
从上面结果可以看出,ArrayList 和LinkedList 都是非线程安全的
----------------------------------------------------------------------------------------------
关于Vector,Vector的本质也是一个数组,数组的优劣势也是它的优劣势。
看jdk 的源码,发现好多方法都是用synchronized修饰的,想当然,我们认为这个是线程安全的。看下面的测试代码:
package com.drafire.testall.Sevice; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.Vector; @SpringBootTest @RunWith(SpringRunner.class) public class VectorClass { private final Vector vector = new Vector(); //修改元素的位置 private final int CHANGE_INDEX = 5; //线程数量 private static final int THREAD_SIZE = 10; //测试线程安全 @Test public void testThreadSafe() { for (int i = 0; i < THREAD_SIZE; i++) { vector.add(i, THREAD_SIZE + i); } MyVectorThread[] myVectorThreads = new MyVectorThread[THREAD_SIZE]; for (int i = 0; i < THREAD_SIZE; i++) { myVectorThreads[i] = new MyVectorThread(i); } for (int i = 0; i < THREAD_SIZE; i++) { //不要调用run方法。因为run()实际上只是跑了主进程一个线程 Thread thread = new Thread(myVectorThreads[i]); thread.start(); } System.out.println("vector[" + CHANGE_INDEX + "]=" + vector.get(CHANGE_INDEX)); } private class MyVectorThread implements Runnable { private int value; public MyVectorThread(int v) { this.value = v; } @Override public void run() { vector.set(CHANGE_INDEX, value); } } }
多次测试,发现上面输出结果,并非都是我们想象中的:vector[5]=9。这是因为,线程安全,指的是单个操作安全,复合操作有问题(我也不懂什么叫复合操作)。
-----------------------------------------------------------------------------------
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型
Array大小固定,ArrayList的大小是动态变化的。
ArrayList提供了更多的方法和特性:比如 :addAll(),removeAll(),iterator()等等。