ArrayList、Vector、LinkedList、CopyOnWriteArrayList解析

文章目录

  • 1. ArrayList
    • 1.1 ArrayList的扩容
  • 2. LinkedList
    • 2.1 ArrayList和LinkedList的区别
  • 3. Vector
    • ArrayList的Vector的区别
  • 4. CopyOnWriteArrayList

1. ArrayList

ArrayList 是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。默认容量是10(从源码中可以看出每次容量扩大为原来的1.5倍,int newCapacity = oldCapacity + (oldCapacity >> 1);)。ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
	......
	
	/**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

	public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }	
	
	public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
	
	public ArrayList(Collection<? extends E> c) {
		......
	}

	private void grow(int minCapacity) {
        	// overflow-conscious code
        	int oldCapacity = elementData.length;
        	int newCapacity = oldCapacity + (oldCapacity >> 1);
        	if (newCapacity - minCapacity < 0)
            		newCapacity = minCapacity;
        	if (newCapacity - MAX_ARRAY_SIZE > 0)
            		newCapacity = hugeCapacity(minCapacity);
        	// minCapacity is usually close to size, so this is a win:
        	elementData = Arrays.copyOf(elementData, newCapacity);
    	}

	public int size() {
        return size;
    }

   	......
}

1.1 ArrayList的扩容

ArrayList的默认容量为10,当插入第11个元素的时候就会扩容,每次扩容增大为原来的1.5倍,可从代码int newCapacity = oldCapacity + (oldCapacity >> 1);看出。

2. LinkedList

LinkedList和ArrayList一样实现了List接口,但是LinkedList是用链表实现的。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
   	transient int size = 0;

	transient Node<E> first;

	transient Node<E> last;

	public LinkedList() {
    	}

	private static class Node<E> {
        	E item;
        	Node<E> next;
        	Node<E> prev;

		Node(Node<E> prev, E element, Node<E> next) {
			this.item = element;
            		this.next = next;
            		this.prev = prev;
            	}
        }

	......
}

2.1 ArrayList和LinkedList的区别

  • 遍历都可以使用普通for循环、foreach循环、Iterator接口实现
  • ArrayList基于数组实现,LinkedList基于链表实现
  • ArrayList随机访问和修改的效率比较高,LinkedList插入和删除的效率比较高

3. Vector

Vector是线程安全的,从源码中有很多的synchronized就可以看出。

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
	......
	protected Object[] elementData;
	protected int elementCount;
	protected int capacityIncrement;

	public Vector(int initialCapacity) {
        	this(initialCapacity, 0);
	}

	public Vector() {
        	this(10);
    	}
	
	public synchronized int capacity() {
        	return elementData.length;
    	}

	public synchronized int size() {
        	return elementCount;
    	}
	......
}

ArrayList的Vector的区别

  • Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。所以在单线程中,ArrayList比Vector性能要高。
  • ArrayList和Vector底层都采用数组进行连续存储,当存储空间不足需要扩容的时候,ArrayList默认增加为原来的1.5倍,Vector默认增加为原来的2倍
  • 查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用Vector和ArrayList都可以。

4. CopyOnWriteArrayList

CopyOnWriteArrayList具有如下特性:

  • 实现了List接口;
  • 内部持有一个ReentrantLock lock = new ReentrantLock();
  • 增加时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array;
  • 增删改都需要获得锁,并且锁只有一把,而读操作不需要获得锁,支持并发。为什么增删改中都需要创建一个新的数组,操作完成之后再赋给原来的引用?这是为了保证get的时候都能获取到元素,如果在增删改过程直接修改原来的数组,可能会造成执行读操作获取不到数据;
  • 内部使用ReentrantLock保证线程安全
public class CopyOnWriteArrayList<E>
	implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    	private static final long serialVersionUID = 8673264195747942595L;
	
	/** The lock protecting all mutators */
	final transient ReentrantLock lock = new ReentrantLock();
	
	/** The array, accessed only via getArray/setArray. */
	private transient volatile Object[] array;

	public boolean add(E e) {
	        final ReentrantLock lock = this.lock;
	        lock.lock();
	        try {
	            Object[] elements = getArray();
	            int len = elements.length;
	            Object[] newElements = Arrays.copyOf(elements, len + 1);
	            newElements[len] = e;
	            setArray(newElements);
	            return true;
	        } finally {
	            lock.unlock();
	        }
	    }
	
	}

	......
}

相关链接:ReentrantLock和synchronized的原理、底层实现、区别

你可能感兴趣的:(集合容器)