Java JUCパッケージソース分析-CopyOnWriteArrayListとCopyOnWriteArraySet
9482 ワード
CopyOnWriteArrayListはスレッドが安全なArrayListと見なすことができ,下位データ構造は配列である.主な実装プロセスはその名前のように、書く(追加、削除、変更)ときに、まずcopyでコピーを出して、それからコピーに操作して、最後にコピーを元の配列に割り当てて、全体のプロセスはReentrantLockのlockの下で完成します.
スレッドの安全を保証するために、読み取りをブロックしないことを目的としています.
データを格納するのはvolatileで修飾された配列であり,マルチスレッドシーンで修正後の最新のデータを読み取ることが保証される.次のように解釈されます.
Java言語仕様では、最適な速度を得るために、スレッドが共有メンバー変数のプライベートコピーを保存し、スレッドが同期コードブロックに入ったり離れたりしたときにのみ共有メンバー変数の元の値と比較できることを示しています.私たちは取得または反復するときにロックをかけていないので、volatile修飾を加えないと、各スレッドが表示するか、修正前の古い値が表示される可能性があります.
配列コピーの過程で大量のArraysを使った.copyof()メソッド、このメソッドは実はSystemを呼び出した.Arraycopy()メソッド
反復プロセスではremove,add,setはサポートされていません
CopyOnWriteArraySetはCopyOnWriteArrayListに完全に基づいており、そのaddメソッドはCopyOnWriteArrayListを呼び出したaddIfAbsent()メソッドである
ソースコード:
CopyOnWriteArraySet:
スレッドの安全を保証するために、読み取りをブロックしないことを目的としています.
データを格納するのはvolatileで修飾された配列であり,マルチスレッドシーンで修正後の最新のデータを読み取ることが保証される.次のように解釈されます.
Java言語仕様では、最適な速度を得るために、スレッドが共有メンバー変数のプライベートコピーを保存し、スレッドが同期コードブロックに入ったり離れたりしたときにのみ共有メンバー変数の元の値と比較できることを示しています.私たちは取得または反復するときにロックをかけていないので、volatile修飾を加えないと、各スレッドが表示するか、修正前の古い値が表示される可能性があります.
配列コピーの過程で大量のArraysを使った.copyof()メソッド、このメソッドは実はSystemを呼び出した.Arraycopy()メソッド
反復プロセスではremove,add,setはサポートされていません
CopyOnWriteArraySetはCopyOnWriteArrayListに完全に基づいており、そのaddメソッドはCopyOnWriteArrayListを呼び出したaddIfAbsent()メソッドである
ソースコード:
public class CopyOnWriteArrayList
implements List, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
// ,
final transient ReentrantLock lock = new ReentrantLock();
// :
private transient volatile Object[] array;
//
final Object[] getArray() {
return array;
}
//
final void setArray(Object[] a) {
array = a;
}
//
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
//
public CopyOnWriteArrayList(Collection extends E> c) {
Object[] elements;
// CopyOnWriteArrayList , Collection
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList>)c).getArray();
else {
// c
elements = c.toArray();
// toArray Object[] Object[]
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
//
setArray(elements);
}
//
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// +1
Object[] newElements = Arrays.copyOf(elements, len + 1);
// ,
newElements[len] = e;
setArray(newElements);
return true;
} finally {
//
lock.unlock();
}
}
//
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
//
int numMoved = len - index;
// copy
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
// +1 , index copy
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
//
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
// a index
private E get(Object[] a, int index) {
return (E) a[index];
}
//
public E get(int index) {
return get(getArray(), index);
}
//
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);
// , , copy
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
// o
private static int indexOf(Object o, Object[] elements,
int index, int fence) {
if (o == null) {
for (int i = index; i < fence; i++)
// null , == o??
if (elements[i] == null)
return i;
} else {
for (int i = index; i < fence; i++)
if (o.equals(elements[i]))
return i;
}
return -1;
}
// o
public int indexOf(Object o) {
Object[] elements = getArray();
return indexOf(o, elements, 0, elements.length);
}
// ,CopyOnWriteArraySet
public boolean addIfAbsent(E e) {
//
Object[] snapshot = getArray();
// indexof e , , false
//
// indexof , indexof
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
private boolean addIfAbsent(E e, Object[] snapshot) {
final ReentrantLock lock = this.lock;
//
lock.lock();
try {
//
Object[] current = getArray();
int len = current.length;
//
// ,
if (snapshot != current) {
// Optimize for lost race to another addXXX operation
//
int common = Math.min(snapshot.length, len);
// : ,for [0,common],
// indexof [common,length], e , return false
// 。
for (int i = 0; i < common; i++)
// [0,common] e, e add ,
// false。 index , 。
if (current[i] != snapshot[i] && eq(e, current[i]))
return false;
// common e
if (indexOf(e, current, common, len) >= 0)
return false;
}
// +1, true
Object[] newElements = Arrays.copyOf(current, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
// !null
private static boolean eq(Object o1, Object o2) {
// o1=null,o2=null, true;
// o1=null,o2!=null, false;
// o1!=null, equals
return (o1 == null) ? o2 == null : o1.equals(o2);
}
// , remove,add,set
public Iterator iterator() {
return new COWIterator(getArray(), 0);
}
//
static final class COWIterator implements ListIterator {
//
private final Object[] snapshot;
// ,
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 void remove() {
throw new UnsupportedOperationException();
}
public void set(E e) {
throw new UnsupportedOperationException();
}
public void add(E e) {
throw new UnsupportedOperationException();
}
}
}
CopyOnWriteArraySet:
public class CopyOnWriteArraySet extends AbstractSet
implements java.io.Serializable {
private static final long serialVersionUID = 5457747651344034263L;
private final CopyOnWriteArrayList al;
// CopyOnWriteArrayList
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList();
}
// add CopyOnWriteArrayList addIfAbsent
public boolean add(E e) {
return al.addIfAbsent(e);
}
// CopyOnWriteArrayList ......
}