ArrayList and LinkedList learning

Summary

ArrayList and LinkedList is an implementation of the List interface to different data structures. They are not thread-safe, thread-unsafe often appear in the expansion of the array, when data is added.

First, what ArrayList and LinkedList that?

ArrayList: ArrayList variable is an array implementation of the List interface.

LinkedList: LinkedList is (two-way) linked list implementation of the List interface.

Second, the two data structures List

1, ArrayList data structure

FIG ArrayList class inherits the following:

ArrayList class inheritance graph

(1-1: ArrayList class inheritance diagram)

storage

ArrayList using an array (elememntData) for storing data, when you create ArrayList default constructor will initialize an empty array.

Expansion

ArrayList using arrays to store data, so when adding data capacity needs to be done to check if you need to insufficient capacity for expansion.

Its new size capacity formula: Capacity = Old New Old Capacity Capacity + / 2

Consider the following expansion process Source:

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

// 计算数组需要的最小容量
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

// 判断是否需要扩容,如果需要则扩容
private void ensureExplicitCapacity(int minCapacity) {
    // modCount表示List结构修改的次数,快速失败机制会用到,快速失败机制在后面会详细说明。
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 新容量=旧容量+旧容量/2
    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);
}
(1-2: ArrayList expansion source array)

2, LinkedList data structure

FIG LinkedList class inherits the following:

LinkedList class inheritance graph

(2-1: LinkedList class inheritance diagram)

storage

LinkedList using doubly linked list to store data. Wherein the linked list of nodes is defined as follows:

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-2: LinkedList storage nodes defined)

Add / remove element operation

Add and delete elements LinkedList actually add to the list node / delete, implementation details are given below, for later discussion thread safe use (note modCount changed).

// 添加元素
public boolean add(E e) {
    // 往链表末尾添加元素
    linkLast(e);
    return true;
}
// 添加结点
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    // 新结点作为尾结点
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode; // 连接结点
    size++;
    modCount++;
}

// 删除元素(删除第一个匹配的元素)
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}
// 删除结点
E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}
(2-3: LinkedList add / delete nodes key codes)

Third, the discussion thread safety

First, confirm that it is important, ArrayList and LinkedList are not thread-safe, will analyze some of the issues under multi-threaded happens below.

1, rapid failure (fail-fast)

Fail-fast, referring to List when using the walker to traverse, if the traversal process, the List has been modified, rapid-fail mechanism is triggered, java.util.ConcurrentModificationException throw an exception.

Quick trigger mechanism fails

Previously talked about the role of modCount record for the number of modifications List of time to traverse the walker, the code is through the value that triggers rapid failure.

Related core code is as follows:

int expectedModCount = modCount;

public E next() {
    checkForComodification();
    try {
        int i = cursor;
        E next = get(i);
        lastRet = i;
        cursor = i + 1;
        return next;
    } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

// 检查修改次数,该方法在类中多次会被调用
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
(1-1:java.util.AbstractList Fragment internal class Itr)

2, when the added element array ArrayList cross-border issues

The array bounds problem occurs on expansion of added element is determined, when the current array reaches capacity short of a threshold element array expansion. Concurrent insert an element of judgment on the size of the array are not need expansion , but the current array is actually just an idle position, and therefore the array bounds exception occurs.

3, the additive element is covered

This abnormal situation as shown in the following code comments:

Multiple threads on the same array assignment position, causing the elements to be covered.

elementData[size++] = e;
// elementData[size] = e;  --- thread1
// elementData[size] = e;  --- thread2
// size++; --- thread1
// size++; --- thread2
(3-1: ArrayList additive element is covered)

A similar analysis, this is also the case when LinkedList add elements.

4, thread-safe List

Synchronization method

All synchronization methods used, such as: Vector, Collections.synchronizedList (list)

Other lock

Other locking achieve thread-safe, such as: ConcurrentLinkedDeque (spin + CAS), CopyOnWriteArrayList (write lock)

Reference material

Guess you like

Origin www.cnblogs.com/guanjianzhuo/p/10926507.html
Recommended