java的集合类主要就是Collection(List、Set)和 Map。
ArrayList和LinkedList都不保证线程安全(事实上常用的集合类都不支持线程安全,线程安全模式的集合类都在juc包中)
ArrayList底层使用的是Object数组、而LinkedList使用的是双向链表(1.6之前使用的是双向循环链表、1.7取消了循环)
ArrayList会浪费一定的空间,空间浪费主要体现在在list列表的结尾会预留一定的容量空间。
LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
小tips:由于ArrayList底层是数组,所以它支持随机读写,类也中实现了RandomAccess接口(这个接口只是为了标识,并无里面内容)。而这个接口却在某些地方起了作用

public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

这是Collections.binarySearch()集合工具类的一个二分查找方法,如果这个类实现了RandomAccess接口就可以利用indexedBinarySearch(也就是随机读写方式get(xx)),否则利用迭代器模式iteratorBinarySearch。
至于基本已经被淘汰的Vector类可以使用juc的CopyOnWriteArrayList或者利用Collections.synchronizedList来包装list

ArrayList源码学习
ArrayList底层是使用obj数组的,会动态的增加容量。使用ensureCapacity操作判断是否来增加 ArrayList 实例的容量(grow实际的扩容方法)。
默认容量为10,每次提升1.5倍
当插入时,我们需要将数组中的所有在插入点后的数据向后移动一位

/**
     * 在此列表中的指定位置插入指定的元素。 
     *先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;
     *再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //arraycopy()方法实现数组自己复制自己
        //elementData:源数组;index:源数组中的起始位置;elementData:目标数组;index + 1:目标数组中的起始位置; size - index:要复制的数组元素的数量;
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }

由于ArrayList是使用obj数组存放内容的,而当使用toArray时,由于存放数据的obj数组后面会有预留位置,所以源码是使用Arrays.copyOf来实现的

/**
     *以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 
     *返回的数组将是“安全的”,因为该列表不保留对它的引用。 (换句话说,这个方法必须分配一个新的数组)。
     *因此,调用者可以自由地修改返回的数组。 此方法充当基于阵列和基于集合的API之间的桥梁。
     */
    public Object[] toArray() {
    //elementData:要复制的数组;size:要复制的长度
        return Arrays.copyOf(elementData, size);
    }

1.arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置
2.copyOf()是系统自动在内部新建一个数组,并返回该数组。
扩容的核心方法(grow):

/**
     * ArrayList扩容的核心方法。
     */
    private void grow(int minCapacity) {
       //elementData为保存ArrayList数据的数组
       ///elementData.length求数组长度elementData.size是求数组中的元素个数
        // oldCapacity为旧容量,newCapacity为新容量
        int oldCapacity = elementData.length;
        //将oldCapacity 右移一位,其效果相当于oldCapacity /2,
        //我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
        if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //再检查新容量是否超出了ArrayList所定义的最大容量, //若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE, //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。 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);
    }

但是有一个小问题,我们要是明确了这个ArrayList是稳定的,不会再删减元素,则可以利用trimToSize方法,避免浪费空间。

/**
     * Trims the capacity of this ArrayList instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an ArrayList instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

LinkedList源码学习
LinkedList内部结构图(也就是一个双向链表):

Java 安全累加 java安全集合类_Java 安全累加

内部结果的私有类Node:

private static class Node<E> {
        E item;//节点值
        Node<E> next;//后继节点
        Node<E> prev;//前驱节点

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

由于元素是利用链表存储的,所以也就不会存在扩容的情况。
toArray方法(就是利用头指针,逐个遍历):

public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        for (Node x = first; x != null; x = x.next)
            result[i++] = x.item;
        return result;
    }