美文网首页
ArrayList的一些个人理解

ArrayList的一些个人理解

作者: yyyfor | 来源:发表于2017-07-22 11:59 被阅读0次

    ArrayList的父类和实现的接口:
    public class ArrayList extends AbstractList
    implements List, RandomAccess, Cloneable, Serializable

    ArrayList 官方API的一些介绍

    ArrayList是一个实现了List接口的可变数组,实现了list的所有可选操作,容许存储所有的元素,包括null。
    size, isEmpty, get, set, iterator, and listIterator operations操作时间复杂度都是常量(O(1)),添加n个元素需要O(n)的时间复杂度。其他的操作都是线性时间。
    每个ArrayList实例都有容量。如果没有定义,ArrayList的初始容量是10,每次添加前都会使用ensureCapacity。
    ArrayList是线程不安全的,如果多个线程同时使用arraylist, 必须在外部synchronized。一般通过同步封装list的object实现,如果没有的话,list必须用Collections.synchronizedList
    来“封装”。

    List list = Collections.synchronizedList(new ArrayList(...));
    

    arrayList class iterator
    and listIterator
    返回的iterators采用了fail-fast的错误机制。当list的iterator产生之后,如果list在结构上有修改,就会抛出ConcurrentModificationException
    异常。

    ArrayList的一些理解

    ArrayList基于数组实现,get和set的效率高。get和set会先进行范围的检查,然后get或者set数据

    public E get(int index) {
            rangeCheck(index);
    
            return elementData(index);
        }
    
    public E set(int index, E element) {
            rangeCheck(index);
    
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
    

    在数组的末尾添加的效率也高

    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    

    但是如果不是在数组的末尾添加数据,需要使用System的arraycopy复制数组,效率不如LinkedList

    public void add(int index, E element) {
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);
            elementData[index] = element;
            size++;
        }
    

    实现了RandomAccess的接口,支持快速的随机访问。

    for (int i=0, n=list.size(); i < n; i++) {     
        list.get(i);
    }
    runs faster than this loop:
    for (Iterator i=list.iterator(); i.hasNext(); ) { 
       i.next();
    }
    

    ArrayList的线程不安全

    ArrayList在性能上比Vector好,但是由于ArrayList的add,remove方法都没有synchronized,所以在多线程操作ArrayList的时候可能会造成得不到想要的结果

    public class ArrayListTest {
        
        public static void main(String[] args) throws InterruptedException {
            
            List<Integer> list = new ArrayList<Integer>();
            
            MyTask3 task = new MyTask3(list);
            for(int i = 0 ; i < 1000; i++) {
                new Thread(task).start();
            }
            
            System.out.println(list.size());
        }
        
    }
    
    class MyTask3 implements Runnable {
    
        List<Integer> list; 
        public MyTask3(List<Integer> list) {
            this.list = list;
        }
    
        @Override
        public void run() {
            for(int i = 0 ; i < 100; i++) {
                list.add(1);        
            }
        }
        
    }
    

    执行以上代码五次的结果:

    99999
    100000
    99900
    Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException
    99873
    

    加上synchronized之后:

    public void run() {
            for(int i = 0 ; i < 100; i++) {
                synchronized (list) {
                    list.add(1);
                }   
            }
        }
    

    执行五次

    95200
    99900
    99700
    99900
    100000
    

    还是没有达到想要的结果。这里我的推测是在其他线程还没有执行完的时候,主线程就执行了System.out.Println。于是在这里加上CountDownLatch。

    public class ArrayListTest {
        public static void main(String[] args) throws InterruptedException {
            List<Integer> list = new ArrayList<Integer>();
            CountDownLatch countDownLatch = new CountDownLatch(1000);
            MyTask3 task = new MyTask3(list, countDownLatch);
            for(int i = 0 ; i < 1000; i++) {
                new Thread(task).start();
            }
            
            countDownLatch.await();
            
            System.out.println(list.size());
        }
        
    }
    
    class MyTask3 implements Runnable {
    
        List<Integer> list;
        CountDownLatch countDownLatch;
        
        public MyTask3(List<Integer> list, CountDownLatch countDownLatch) {
            this.list = list;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            for(int i = 0 ; i < 100; i++) {
                synchronized (list) {
                    list.add(1);
                }
                    
                
            }
            countDownLatch.countDown();
        }
        
    }
    

    再执行五次:

    100000
    100000
    100000
    100000
    100000
    

    结果完全正确。

    以上是我基于ArrayList的一些简单的理解。 站在巨人的肩膀上才能看的更高,其中也引用了前辈们的一些例子和方法。深深的感觉在技术这条道路上还有很多值得深入研究和学习的地方,接下来准备深入研究一下多线程的相关东西。

    相关文章

      网友评论

          本文标题:ArrayList的一些个人理解

          本文链接:https://www.haomeiwen.com/subject/xxxukxtx.html