Collections.synchronizedList與CopyOnWriteArrayList

Collections.synchronizedList和CopyOnWriteArrayList在併發場景下都可以使用,Collections.synchronizedList是Collections下的匿名內部類,而CopyOnWriteArrayList是juc包下的。

CopyOnWriteArrayList

  推薦使用,juc包下的都是爲併發而生,可以從字面意思就知道CopyOnWriteArrayList是每次寫的時候都會拷貝一份進行操作,是不是就是讀寫分離。

  add(E e) 源碼

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;

/**
 * Gets the array.  Non-private so as to also be accessible
 * from CopyOnWriteArraySet class.
 */
final Object[] getArray() {
    return array;
}

/**
 * Sets the array.
 */
final void setArray(Object[] a) {
    array = a;
}


 /**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 */
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進行加鎖操作,調用getArray獲取當前對象的屬性Object[] array,且使用Arrays.copyOf拷貝一個新的數組,將當前數據加入新數組中,並且重新賦值到array,最後釋放鎖。

如果當前讀操作正好有寫操作,寫的時候是對副本進行操作,而讀的是當前對象,互不影響

/**
 * {@inheritDoc}
 *
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    return get(getArray(), index);
}

CopyOnWriteArrayList就是寫的時候對拷貝對象進行操作,這樣一來讀寫分離保證了List的一致性。

 

Collections.synchronizedList

  Collections中的一個靜態內部類,傳入一個List,它可以將一個非安全的List轉換成一個安全的List,內部使用synchronized對操作進行加鎖。

public static <T> List<T> synchronizedList(List<T> list) {
    return (list instanceof RandomAccess ?
            new SynchronizedRandomAccessList<>(list) :
            new SynchronizedList<>(list));
}

當傳入一個list對象是會進行判斷是否RandomAccess,根據true或false執行不同的構造函數。 有意思的是SynchronizedRandomAccessList繼承於SynchronizedList。

 

繼承關係

      

 

 

 SynchronizedList源碼

/**
 * @serial include
 */
static class SynchronizedList<E>
    extends SynchronizedCollection<E>
    implements List<E> {
    private static final long serialVersionUID = -7754090372962971524L;

    final List<E> list;

    SynchronizedList(List<E> list) {
        super(list);
        this.list = list;
    }
    SynchronizedList(List<E> list, Object mutex) {
        super(list, mutex);
        this.list = list;
    }

    public boolean equals(Object o) {
        if (this == o)
            return true;
        synchronized (mutex) {return list.equals(o);}
    }
    public int hashCode() {
        synchronized (mutex) {return list.hashCode();}
    }

    public E get(int index) {
        synchronized (mutex) {return list.get(index);}
    }
    public E set(int index, E element) {
        synchronized (mutex) {return list.set(index, element);}
    }
    public void add(int index, E element) {
        synchronized (mutex) {list.add(index, element);}
    }
    public E remove(int index) {
        synchronized (mutex) {return list.remove(index);}
    }

    public int indexOf(Object o) {
        synchronized (mutex) {return list.indexOf(o);}
    }
    public int lastIndexOf(Object o) {
        synchronized (mutex) {return list.lastIndexOf(o);}
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        synchronized (mutex) {return list.addAll(index, c);}
    }

    public ListIterator<E> listIterator() {
        return list.listIterator(); // Must be manually synched by user
    }

    public ListIterator<E> listIterator(int index) {
        return list.listIterator(index); // Must be manually synched by user
    }

    public List<E> subList(int fromIndex, int toIndex) {
        synchronized (mutex) {
            return new SynchronizedList<>(list.subList(fromIndex, toIndex),
                                        mutex);
        }
    }

    @Override
    public void replaceAll(UnaryOperator<E> operator) {
        synchronized (mutex) {list.replaceAll(operator);}
    }
    @Override
    public void sort(Comparator<? super E> c) {
        synchronized (mutex) {list.sort(c);}
    }

    /**
     * SynchronizedRandomAccessList instances are serialized as
     * SynchronizedList instances to allow them to be deserialized
     * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
     * This method inverts the transformation.  As a beneficial
     * side-effect, it also grafts the RandomAccess marker onto
     * SynchronizedList instances that were serialized in pre-1.4 JREs.
     *
     * Note: Unfortunately, SynchronizedRandomAccessList instances
     * serialized in 1.4.1 and deserialized in 1.4 will become
     * SynchronizedList instances, as this method was missing in 1.4.
     */
    private Object readResolve() {
        return (list instanceof RandomAccess
                ? new SynchronizedRandomAccessList<>(list)
                : this);
    }
}

內部使用synchronized來進行加鎖,而鎖的對象mutex就是當前對象this。在其父類SynchronizedCollection中定義的。

    /**
     * @serial include
     */
    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
        private static final long serialVersionUID = 3053995032091335093L;

        final Collection<E> c;  // Backing Collection
        final Object mutex;     // Object on which to synchronize

值的注意的是在SynchronizedList中存在兩個沒有加鎖的方法,需要用戶手動加鎖的,如下:

public ListIterator<E> listIterator() {
        return list.listIterator(); // Must be manually synched by user
    }

public ListIterator<E> listIterator(int index) {
        return list.listIterator(index); // Must be manually synched by user
    }

在SynchronizedCollection中也存在沒加鎖的方法,迭代器,分割,流操作都需要手動加鎖!!

 /**
 * @serial include
 */
static class SynchronizedCollection<E> implements Collection<E>, Serializable {

    public Iterator<E> iterator() {
        return c.iterator(); // Must be manually synched by user!
    }

    @Override
    public Spliterator<E> spliterator() {
        return c.spliterator(); // Must be manually synched by user!
    }
    @Override
    public Stream<E> stream() {
        return c.stream(); // Must be manually synched by user!
    }
    @Override
    public Stream<E> parallelStream() {
        return c.parallelStream(); // Must be manually synched by user!
    }

}

在Collections類中,其實就是利用了同步代碼塊來保證數據的安全,而有幾個方法需要手動進行加鎖處理。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章