ArrayList的一些个人理解

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 list = new ArrayList();
        
        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 list; 
    public MyTask3(List 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 list = new ArrayList();
        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 list;
    CountDownLatch countDownLatch;
    
    public MyTask3(List 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的一些个人理解)