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

 

posted on 2021-08-20 15:13  多看多记多写  阅读(166)  评论(0)    收藏  举报