java并发编程之美-阅读记录5
生活随笔
收集整理的這篇文章主要介紹了
java并发编程之美-阅读记录5
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
java并發包中的并發List
5.1CopeOnWriteArrayList
并發包中的并發List只有CopyOnWriteArrayList,該類是一個線程安全的arraylist,對其進行的修改操作都是在底層的一個復制數組上進行的,也就是使用了寫時復制策略。
該類的結構:
public class CopyOnWriteArrayList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {private static final long serialVersionUID = 8673264195747942595L;// 可重入的獨占鎖,用來保證對arraylist的修改操作,同一時間只有一個線程final transient ReentrantLock lock = new ReentrantLock();// 存放對象的底層數組 內存可見性private transient volatile Object[] array;// 基于硬件的原子操作了Unsafeprivate static final sun.misc.Unsafe UNSAFE;// 鎖的偏移量private static final long lockOffset;static {try {UNSAFE = sun.misc.Unsafe.getUnsafe();Class<?> k = CopyOnWriteArrayList.class;lockOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("lock"));} catch (Exception e) {throw new Error(e);}} }問題:
何時初始化list,初始化list的大小是多少,list是有限大小嗎?? ? copyonwriteArraylist是無界數組
如何保證線程安全,比如多個線程進行讀寫時如何保證是線程安全的?
如何保證迭代器遍歷list時的數據一致性?
5.2源碼分析
1、初始化
構造函數:
// 空的listpublic CopyOnWriteArrayList() {setArray(new Object[0]);}// 入參為Collection類型的集合,該構造會將集合中的元素復制到list中public CopyOnWriteArrayList(Collection<? extends E> c) {Object[] elements;if (c.getClass() == CopyOnWriteArrayList.class)elements = ((CopyOnWriteArrayList<?>)c).getArray();else {elements = c.toArray();// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elements.getClass() != Object[].class)elements = Arrays.copyOf(elements, elements.length, Object[].class);}setArray(elements);}// 入參為泛型數組,將數組復制到list的底層數組中public CopyOnWriteArrayList(E[] toCopyIn) {setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));}2、添加元素add方法
// 添加元素,在list的末尾添加public boolean add(E e) {final ReentrantLock lock = this.lock;// 獲取獨占鎖lock.lock();try {// 獲取copyOnWriteArrayList底層數組Object[] elements = getArray();int len = elements.length;// 復制一份新的數組,比原數組大一,所以CopyOnWriteArraylist是一個無界數組Object[] newElements = Arrays.copyOf(elements, len + 1);// 將要添加的元素放到新數組的最后位置newElements[len] = e;// 使用新數組替換原來的數組setArray(newElements);return true;} finally {// 操作完畢后,釋放獨占鎖lock.unlock();}}3、獲取元素,此時就會產生寫時復制的弱一致性問題:當線程a獲取到地層數組后,但是沒有執行get(Object[] a,int index)方法,此時線程b操作該集合,刪除了一個元素(刪除的是復制出的新數組中的數據,同時會使用新數組覆蓋舊數組),name線程a繼續獲取執行位置的數據,此時底層數組仍然是之前沒有刪除數據的數組,這樣就產生了弱一致性問題。
// 直接獲取底層數組指定索引位置的數據private E get(Object[] a, int index) {return (E) a[index];}// 獲取指定索引出的值 getArray方法返回底層數組public E get(int index) {return get(getArray(), index);}4、修改指定位置的元素
public E set(int index, E element) {final ReentrantLock lock = this.lock;// 獲取獨占鎖lock.lock();try {// 獲取底層數組Object[] elements = getArray();// 根據索引獲取要修改的值E oldValue = get(elements, index);// 如果新值不等于舊值時,就會復制一份數組,將新值設置進入,然后用新數組覆蓋就數組if (oldValue != element) {int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len);newElements[index] = element;setArray(newElements);} else {// Not quite a no-op; ensures volatile write semantics// 舊數組重新覆蓋舊數組--> 這一步雖然沒有改變數組,但是為了保證volatitle語義,仍然會重新設置一次setArray(elements);}return oldValue;} finally {// 釋放鎖lock.unlock();}}5、刪除元素
public E remove(int index) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;// 獲取要刪除索引位置的元素E oldValue = get(elements, index);// 計算要移動的元素的數量int numMoved = len - index - 1;// 要移動的元素為0,則代表刪除的是最后一個元素if (numMoved == 0)setArray(Arrays.copyOf(elements, len - 1));else {// 要刪除的不是最后一個,則新建一個len-1長度的數組Object[] newElements = new Object[len - 1];// 同時以要刪除的索引index為分界線,復制0-index,index+1 - len的元素System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index + 1, newElements, index,numMoved);setArray(newElements);}return oldValue;} finally {lock.unlock();}}6、弱一致性的迭代器
所謂弱一致性是指:返回迭代器后,其他線程對list的操作(增刪改)對迭代器是不可見的。
public Iterator<E> iterator() {return new COWIterator<E>(getArray(), 0);}// 可以看到迭代器中的方法,不能增刪改,相應的方法會拋出異常static final class COWIterator<E> implements ListIterator<E> {/** Snapshot of the array */private final Object[] snapshot;/** Index of element to be returned by subsequent call to next. */private int cursor;private COWIterator(Object[] elements, int initialCursor) {cursor = initialCursor;snapshot = elements;}public boolean hasNext() {return cursor < snapshot.length;}public boolean hasPrevious() {return cursor > 0;}@SuppressWarnings("unchecked")public E next() {if (! hasNext())throw new NoSuchElementException();return (E) snapshot[cursor++];}@SuppressWarnings("unchecked")public E previous() {if (! hasPrevious())throw new NoSuchElementException();return (E) snapshot[--cursor];}public int nextIndex() {return cursor;}public int previousIndex() {return cursor-1;}public void remove() {throw new UnsupportedOperationException();}public void set(E e) {throw new UnsupportedOperationException();}public void add(E e) {throw new UnsupportedOperationException();}@Overridepublic void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);Object[] elements = snapshot;final int size = elements.length;for (int i = cursor; i < size; i++) {@SuppressWarnings("unchecked") E e = (E) elements[i];action.accept(e);}cursor = size;}}弱一致性:
package com.nxz.blog.otherTest;import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList;public class TestThread003 {private static CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();/*** 測試CopyOnWriteArrayList的弱一致性問題* 如果輸出結果是:test1 test2 test3 test4 則說明該類具有弱一致性*/public static void main(String[] args) throws InterruptedException {copyOnWriteArrayList.add("test1");copyOnWriteArrayList.add("test2");copyOnWriteArrayList.add("test3");copyOnWriteArrayList.add("test4");Thread t = new Thread(new Runnable() {@Overridepublic void run() {copyOnWriteArrayList.add("runnabl1");copyOnWriteArrayList.add("runnabl2");copyOnWriteArrayList.add("runnabl3");}});Iterator<String> iterator = copyOnWriteArrayList.iterator();// 等待線程執行完畢t.join();while (iterator.hasNext()) {System.out.println(iterator.next());}} } 結果: test1 test2 test3 test4?
總結
以上是生活随笔為你收集整理的java并发编程之美-阅读记录5的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java并发编程之美-阅读记录4
- 下一篇: java并发编程之美-阅读记录6