ArrayList和LinkedList
ArrayList的底层是数组,它是有序的,是线程不安全的,list的实现类中只有vector是线程安全的,它的默认容量是10,是容量是10而不是size()是10,每次扩容到原来的1.5倍,扩容这个操作是用了位移的。ArrayList的随机读取很快,因为底层是数组,直接根据角标读取。但是增加和删除的速度就要要看位置了,增加和删除的底层都是用的原生的System.arraycopy方法,比如add(E e),这个方法增加元素就很快,因为它只是往尾部增加元素,后面也没有元素需要移动。但是往中间或者开头添加或删除元素就非常的慢,因为每次都要复制移动元素
LinkedList的底层是双向链表,它也是有序的,是线程不安全的,list的实现类中只有vector是线程安全的,LinkedList使用first和last引用分别指向第一个和最后一个元素,当链表为空的时候first和last都指向null,LinkedList可存放null元素,因为其实双向链表所以查询的时候可以从前往后也可以从后往前查,查找使用的是二分查找法
线程安全:
1 、两者都不是线程安全的,如果这两个对象的内存空间被多线程共享,而会出现一个线程正在修改数值的时候,被另外一个线程读到原来的值。也就是经常说的“脏读”。
另外,ArrayList在内存不足时,会发生扩容,扩容时多线程的读写都会存在问题。
2、 变成多线程安全,有两种方案
(1)使用容易提供的同步方法Collections.synchronizedList(new LinkedList())。每次在写入的时候,锁住临界区,保证数据的一致性
(2)使用线程安全的vector等对象
经过多次测试发现 当要操作头部元素的时候选用LinkedList,其他位置的元素都可以选用ArrayList
看这段代码,分别在ArrayList和linkedList的头部和尾部添加元素:
System.out.println("开始添加元素..."); LinkedList<Object> linkedList = new LinkedList<>(); ArrayList<Object> arrayList = new ArrayList<>(); long startTime = System.currentTimeMillis(); for (int i = 1; i < 30000000; i++) { linkedList.add(i); arrayList.add(i); } long endTime = System.currentTimeMillis(); System.out.println("添加元素耗时:" + (endTime - startTime)); long l = System.currentTimeMillis(); linkedList.add(0, 1); long l1 = System.currentTimeMillis(); linkedList.add(30000000 / 2, 1); long l2 = System.currentTimeMillis(); linkedList.add(30000000, 1); long l3 = System.currentTimeMillis(); System.out.println("linkedList在头部添加元素耗时:" + (l1 - l)); System.out.println("linkedList在中间添加元素耗时:" + (l2 - l1)); System.out.println("linkedList在尾部添加元素耗时:" + (l3 - l2)); System.out.println(); long a = System.currentTimeMillis(); arrayList.add(0, 1); long a1 = System.currentTimeMillis(); arrayList.add(30000000 / 2, 1); long a2 = System.currentTimeMillis(); arrayList.add(30000000, 1); long a3 = System.currentTimeMillis(); System.out.println("arrayList在头部添加元素耗时:" + (a1 - a)); System.out.println("arrayList在中间添加元素耗时:" + (a2 - a1)); System.out.println("arrayList在尾部添加元素耗时:" + (a3 - a2));
结果如下:
多次测试后发现,如果元素较多时,需要经常在头部操作元素就选LinkedList,在尾部操作元素这两个都可以,在中间操作元素的话还是选择ArrayList