无标题文章

```

/*

* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*/

/*

* Written by Doug Lea with assistance from members of JCP JSR-166

* Expert Group.  Adapted and released, under explicit permission,

* from JDK ArrayList.java which carries the following copyright:

*

* Copyright 1997 by Sun Microsystems, Inc.,

* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.

* All rights reserved.

*/

packagejava.util.concurrent;

importjava.util.AbstractList;

importjava.util.Arrays;

importjava.util.Collection;

importjava.util.Comparator;

importjava.util.ConcurrentModificationException;

importjava.util.Iterator;

importjava.util.List;

importjava.util.ListIterator;

importjava.util.NoSuchElementException;

importjava.util.Objects;

importjava.util.RandomAccess;

importjava.util.Spliterator;

importjava.util.Spliterators;

importjava.util.concurrent.locks.ReentrantLock;

importjava.util.function.Consumer;

importjava.util.function.Predicate;

importjava.util.function.UnaryOperator;

/**

* A thread-safe variant of {@linkjava.util.ArrayList} in which all mutative

* operations ({@codeadd}, {@codeset}, and so on) are implemented by

* making a fresh copy of the underlying array.

*

*

This is ordinarily too costly, but may bemoreefficient

* than alternatives when traversal operations vastly outnumber

* mutations, and is useful when you cannot or don't want to

* synchronize traversals, yet need to preclude interference among

* concurrent threads.  The "snapshot" style iterator method uses a

* reference to the state of the array at the point that the iterator

* was created. This array never changes during the lifetime of the

* iterator, so interference is impossible and the iterator is

* guaranteed not to throw {@codeConcurrentModificationException}.

* The iterator will not reflect additions, removals, or changes to

* the list since the iterator was created.  Element-changing

* operations on iterators themselves ({@coderemove}, {@codeset}, and

* {@codeadd}) are not supported. These methods throw

* {@codeUnsupportedOperationException}.

*

*

All elements are permitted, including {@codenull}.

*

*

Memory consistency effects: As with other concurrent

* collections, actions in a thread prior to placing an object into a

* {@codeCopyOnWriteArrayList}

*happen-before

* actions subsequent to the access or removal of that element from

* the {@codeCopyOnWriteArrayList} in another thread.

*

*

This class is a member of the

*

* Java Collections Framework.

*

*@since1.5

*@authorDoug Lea

*@paramthe type of elements held in this collection

*/

public classCopyOnWriteArrayList

implementsList,RandomAccess,Cloneable,java.io.Serializable {

private static final longserialVersionUID=8673264195747942595L;

/** The lock protecting all mutators */

final transientReentrantLocklock=newReentrantLock();

/** The array, accessed only via getArray/setArray. */

private transient volatileObject[]array;

/**

* Gets the array.  Non-private so as to also be accessible

* from CopyOnWriteArraySet class.

*/

finalObject[]getArray() {

returnarray;

}

/**

* Sets the array.

*/

final voidsetArray(Object[] a) {

array= a;

}

/**

* Creates an empty list.

*/

publicCopyOnWriteArrayList() {

setArray(newObject[0]);

}

/**

* Creates a list containing the elements of the specified

* collection, in the order they are returned by the collection's

* iterator.

*

*@paramcthe collection of initially held elements

*@throwsNullPointerException if the specified collection is null

*/

publicCopyOnWriteArrayList(Collection 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);

}

/**

* Creates a list holding a copy of the given array.

*

*@paramtoCopyInthe array (a copy of this array is used as the

*        internal array)

*@throwsNullPointerException if the specified array is null

*/

publicCopyOnWriteArrayList(E[] toCopyIn) {

setArray(Arrays.copyOf(toCopyIn,toCopyIn.length,Object[].class));

}

/**

* Returns the number of elements in this list.

*

*@returnthe number of elements in this list

*/

public intsize() {

returngetArray().length;

}

/**

* Returns {@codetrue} if this list contains no elements.

*

*@return{@codetrue} if this list contains no elements

*/

public booleanisEmpty() {

returnsize() ==0;

}

/**

* Tests for equality, coping with nulls.

*/

private static booleaneq(Object o1,Object o2) {

return(o1 ==null) ? o2 ==null: o1.equals(o2);

}

/**

* static version of indexOf, to allow repeated calls without

* needing to re-acquire array each time.

*@paramoelement to search for

*@paramelementsthe array

*@paramindexfirst index to search

*@paramfenceone past last index to search

*@returnindex of element, or -1 if absent

*/

private static intindexOf(Object o,Object[] elements,

intindex, intfence) {

if(o ==null) {

for(inti = index;i < fence;i++)

if(elements[i] ==null)

returni;

}else{

for(inti = index;i < fence;i++)

if(o.equals(elements[i]))

returni;

}

return-1;

}

/**

* static version of lastIndexOf.

*@paramoelement to search for

*@paramelementsthe array

*@paramindexfirst index to search

*@returnindex of element, or -1 if absent

*/

private static intlastIndexOf(Object o,Object[] elements, intindex) {

if(o ==null) {

for(inti = index;i >=0;i--)

if(elements[i] ==null)

returni;

}else{

for(inti = index;i >=0;i--)

if(o.equals(elements[i]))

returni;

}

return-1;

}

/**

* Returns {@codetrue} if this list contains the specified element.

* More formally, returns {@codetrue} if and only if this list contains

* at least one element {@codee} such that

*(o==null ? e==null : o.equals(e)).

*

*@paramoelement whose presence in this list is to be tested

*@return{@codetrue} if this list contains the specified element

*/

public booleancontains(Object o) {

Object[] elements = getArray();

returnindexOf(o,elements,0,elements.length) >=0;

}

/**

* {@inheritDoc}

*/

public intindexOf(Object o) {

Object[] elements = getArray();

returnindexOf(o,elements,0,elements.length);

}

/**

* Returns the index of the first occurrence of the specified element in

* this list, searching forwards from {@codeindex}, or returns -1 if

* the element is not found.

* More formally, returns the lowest index {@codei} such that

*(i >= index && (e==null ? get(i)==null : e.equals(get(i)))),

* or -1 if there is no such index.

*

*@parameelement to search for

*@paramindexindex to start searching from

*@returnthe index of the first occurrence of the element in

*        this list at position {@codeindex} or later in the list;

*        {@code-1} if the element is not found.

*@throwsIndexOutOfBoundsException if the specified index is negative

*/

public intindexOf(Ee, intindex) {

Object[] elements = getArray();

returnindexOf(e,elements,index,elements.length);

}

/**

* {@inheritDoc}

*/

public intlastIndexOf(Object o) {

Object[] elements = getArray();

returnlastIndexOf(o,elements,elements.length-1);

}

/**

* Returns the index of the last occurrence of the specified element in

* this list, searching backwards from {@codeindex}, or returns -1 if

* the element is not found.

* More formally, returns the highest index {@codei} such that

*(i <= index && (e==null ? get(i)==null : e.equals(get(i)))),

* or -1 if there is no such index.

*

*@parameelement to search for

*@paramindexindex to start searching backwards from

*@returnthe index of the last occurrence of the element at position

*        less than or equal to {@codeindex} in this list;

*        -1 if the element is not found.

*@throwsIndexOutOfBoundsException if the specified index is greater

*        than or equal to the current size of this list

*/

public intlastIndexOf(Ee, intindex) {

Object[] elements = getArray();

returnlastIndexOf(e,elements,index);

}

/**

* Returns a shallow copy of this list.  (The elements themselves

* are not copied.)

*

*@returna clone of this list

*/

publicObjectclone() {

try{

@SuppressWarnings("unchecked")

CopyOnWriteArrayList clone =

(CopyOnWriteArrayList)super.clone();

clone.resetLock();

returnclone;

}catch(CloneNotSupportedException e) {

// this shouldn't happen, since we are Cloneable

throw newInternalError();

}

}

/**

* Returns an array containing all of the elements in this list

* in proper sequence (from first to last element).

*

*

The returned array will be "safe" in that no references to it are

* maintained by this list.  (In other words, this method must allocate

* a new array).  The caller is thus free to modify the returned array.

*

*

This method acts as bridge between array-based and collection-based

* APIs.

*

*@returnan array containing all the elements in this list

*/

publicObject[]toArray() {

Object[] elements = getArray();

returnArrays.copyOf(elements,elements.length);

}

/**

* Returns an array containing all of the elements in this list in

* proper sequence (from first to last element); the runtime type of

* the returned array is that of the specified array.  If the list fits

* in the specified array, it is returned therein.  Otherwise, a new

* array is allocated with the runtime type of the specified array and

* the size of this list.

*

*

If this list fits in the specified array with room to spare

* (i.e., the array has more elements than this list), the element in

* the array immediately following the end of the list is set to

* {@codenull}.  (This is useful in determining the length of this

* listonlyif the caller knows that this list does not contain

* any null elements.)

*

*

Like the {@link#toArray()} method, this method acts as bridge between

* array-based and collection-based APIs.  Further, this method allows

* precise control over the runtime type of the output array, and may,

* under certain circumstances, be used to save allocation costs.

*

*

Suppose {@codex} is a list known to contain only strings.

* The following code can be used to dump the list into a newly

* allocated array of {@codeString}:

*

*

{@codeString[] y = x.toArray(new String[0]);}

*

* Note that {@codetoArray(new Object[0])} is identical in function to

* {@codetoArray()}.

*

*@paramathe array into which the elements of the list are to

*          be stored, if it is big enough; otherwise, a new array of the

*          same runtime type is allocated for this purpose.

*@returnan array containing all the elements in this list

*@throwsArrayStoreException if the runtime type of the specified array

*        is not a supertype of the runtime type of every element in

*        this list

*@throwsNullPointerException if the specified array is null

*/

@SuppressWarnings("unchecked")

publicT[]toArray(Ta[]) {

Object[] elements = getArray();

intlen = elements.length;

if(a.length< len)

return(T[]) Arrays.copyOf(elements,len,a.getClass());

else{

System.arraycopy(elements,0,a,0,len);

if(a.length> len)

a[len] =null;

returna;

}

}

// Positional Access Operations

@SuppressWarnings("unchecked")

privateEget(Object[] a, intindex) {

return(E) a[index];

}

/**

* {@inheritDoc}

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEget(intindex) {

returnget(getArray(),index);

}

/**

* Replaces the element at the specified position in this list with the

* specified element.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEset(intindex,Eelement) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

EoldValue = get(elements,index);

if(oldValue != element) {

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len);

newElements[index] = element;

setArray(newElements);

}else{

// Not quite a no-op; ensures volatile write semantics

setArray(elements);

}

returnoldValue;

}finally{

lock.unlock();

}

}

/**

* Appends the specified element to the end of this list.

*

*@parameelement to be appended to this list

*@return{@codetrue} (as specified by {@linkCollection#add})

*/

public booleanadd(Ee) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len +1);

newElements[len] = e;

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Inserts the specified element at the specified position in this

* list. Shifts the element currently at that position (if any) and

* any subsequent elements to the right (adds one to their indices).

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

public voidadd(intindex,Eelement) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(index > len || index <0)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+len);

Object[] newElements;

intnumMoved = len - index;

if(numMoved ==0)

newElements = Arrays.copyOf(elements,len +1);

else{

newElements =newObject[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();

}

}

/**

* Removes the element at the specified position in this list.

* Shifts any subsequent elements to the left (subtracts one from their

* indices).  Returns the element that was removed from the list.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEremove(intindex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

EoldValue = get(elements,index);

intnumMoved = len - index -1;

if(numMoved ==0)

setArray(Arrays.copyOf(elements,len -1));

else{

Object[] newElements =newObject[len -1];

System.arraycopy(elements,0,newElements,0,index);

System.arraycopy(elements,index +1,newElements,index,

numMoved);

setArray(newElements);

}

returnoldValue;

}finally{

lock.unlock();

}

}

/**

* Removes the first occurrence of the specified element from this list,

* if it is present.  If this list does not contain the element, it is

* unchanged.  More formally, removes the element with the lowest index

* {@codei} such that

*(o==null ? get(i)==null : o.equals(get(i)))

* (if such an element exists).  Returns {@codetrue} if this list

* contained the specified element (or equivalently, if this list

* changed as a result of the call).

*

*@paramoelement to be removed from this list, if present

*@return{@codetrue} if this list contained the specified element

*/

public booleanremove(Object o) {

Object[] snapshot = getArray();

intindex =indexOf(o,snapshot,0,snapshot.length);

return(index <0) ?false: remove(o,snapshot,index);

}

/**

* A version of remove(Object) using the strong hint that given

* recent snapshot contains o at the given index.

*/

private booleanremove(Object o,Object[] snapshot, intindex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] current = getArray();

intlen = current.length;

if(snapshot != current) findIndex: {

intprefix = Math.min(index,len);

for(inti =0;i < prefix;i++) {

if(current[i] != snapshot[i] &&eq(o,current[i])) {

index = i;

breakfindIndex;

}

}

if(index >= len)

return false;

if(current[index] == o)

breakfindIndex;

index =indexOf(o,current,index,len);

if(index <0)

return false;

}

Object[] newElements =newObject[len -1];

System.arraycopy(current,0,newElements,0,index);

System.arraycopy(current,index +1,

newElements,index,

len - index -1);

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Removes from this list all of the elements whose index is between

* {@codefromIndex}, inclusive, and {@codetoIndex}, exclusive.

* Shifts any succeeding elements to the left (reduces their index).

* This call shortens the list by {@code(toIndex - fromIndex)} elements.

* (If {@codetoIndex==fromIndex}, this operation has no effect.)

*

*@paramfromIndexindex of first element to be removed

*@paramtoIndexindex after last element to be removed

*@throwsIndexOutOfBoundsException if fromIndex or toIndex out of range

*        ({@codefromIndex < 0 || toIndex > size() || toIndex < fromIndex})

*/

voidremoveRange(intfromIndex, inttoIndex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(fromIndex <0|| toIndex > len || toIndex < fromIndex)

throw newIndexOutOfBoundsException();

intnewlen = len - (toIndex - fromIndex);

intnumMoved = len - toIndex;

if(numMoved ==0)

setArray(Arrays.copyOf(elements,newlen));

else{

Object[] newElements =newObject[newlen];

System.arraycopy(elements,0,newElements,0,fromIndex);

System.arraycopy(elements,toIndex,newElements,

fromIndex,numMoved);

setArray(newElements);

}

}finally{

lock.unlock();

}

}

/**

* Appends the element, if not present.

*

*@parameelement to be added to this list, if absent

*@return{@codetrue} if the element was added

*/

public booleanaddIfAbsent(Ee) {

Object[] snapshot = getArray();

returnindexOf(e,snapshot,0,snapshot.length) >=0?false:

addIfAbsent(e,snapshot);

}

/**

* A version of addIfAbsent using the strong hint that given

* recent snapshot does not contain e.

*/

private booleanaddIfAbsent(Ee,Object[] snapshot) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] current = getArray();

intlen = current.length;

if(snapshot != current) {

// Optimize for lost race to another addXXX operation

intcommon = Math.min(snapshot.length,len);

for(inti =0;i < common;i++)

if(current[i] != snapshot[i] &&eq(e,current[i]))

return false;

if(indexOf(e,current,common,len) >=0)

return false;

}

Object[] newElements = Arrays.copyOf(current,len +1);

newElements[len] = e;

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Returns {@codetrue} if this list contains all of the elements of the

* specified collection.

*

*@paramccollection to be checked for containment in this list

*@return{@codetrue} if this list contains all of the elements of the

*        specified collection

*@throwsNullPointerException if the specified collection is null

*@see#contains(Object)

*/

public booleancontainsAll(Collection c) {

Object[] elements = getArray();

intlen = elements.length;

for(Object e : c) {

if(indexOf(e,elements,0,len) <0)

return false;

}

return true;

}

/**

* Removes from this list all of its elements that are contained in

* the specified collection. This is a particularly expensive operation

* in this class because of the need for an internal temporary array.

*

*@paramccollection containing elements to be removed from this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsClassCastException if the class of an element of this list

*        is incompatible with the specified collection

*        (optional)

*@throwsNullPointerException if this list contains a null element and the

*        specified collection does not permit null elements

*        (optional),

*        or if the specified collection is null

*@see#remove(Object)

*/

public booleanremoveAll(Collection c) {

if(c ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

// temp array holds those elements we know we want to keep

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

Object element = elements[i];

if(!c.contains(element))

temp[newlen++] = element;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

/**

* Retains only the elements in this list that are contained in the

* specified collection.  In other words, removes from this list all of

* its elements that are not contained in the specified collection.

*

*@paramccollection containing elements to be retained in this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsClassCastException if the class of an element of this list

*        is incompatible with the specified collection

*        (optional)

*@throwsNullPointerException if this list contains a null element and the

*        specified collection does not permit null elements

*        (optional),

*        or if the specified collection is null

*@see#remove(Object)

*/

public booleanretainAll(Collection c) {

if(c ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

// temp array holds those elements we know we want to keep

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

Object element = elements[i];

if(c.contains(element))

temp[newlen++] = element;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

/**

* Appends all of the elements in the specified collection that

* are not already contained in this list, to the end of

* this list, in the order that they are returned by the

* specified collection's iterator.

*

*@paramccollection containing elements to be added to this list

*@returnthe number of elements added

*@throwsNullPointerException if the specified collection is null

*@see#addIfAbsent(Object)

*/

public intaddAllAbsent(Collection c) {

Object[] cs = c.toArray();

if(cs.length==0)

return0;

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

intadded =0;

// uniquify and compact elements in cs

for(inti =0;i < cs.length;++i) {

Object e = cs[i];

if(indexOf(e,elements,0,len) <0&&

indexOf(e,cs,0,added) <0)

cs[added++] = e;

}

if(added >0) {

Object[] newElements = Arrays.copyOf(elements,len + added);

System.arraycopy(cs,0,newElements,len,added);

setArray(newElements);

}

returnadded;

}finally{

lock.unlock();

}

}

/**

* Removes all of the elements from this list.

* The list will be empty after this call returns.

*/

public voidclear() {

finalReentrantLock lock =this.lock;

lock.lock();

try{

setArray(newObject[0]);

}finally{

lock.unlock();

}

}

/**

* Appends all of the elements in the specified collection to the end

* of this list, in the order that they are returned by the specified

* collection's iterator.

*

*@paramccollection containing elements to be added to this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsNullPointerException if the specified collection is null

*@see#add(Object)

*/

public booleanaddAll(Collection c) {

Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?

((CopyOnWriteArrayList)c).getArray() : c.toArray();

if(cs.length==0)

return false;

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len ==0&& cs.getClass() == Object[].class)

setArray(cs);

else{

Object[] newElements = Arrays.copyOf(elements,len + cs.length);

System.arraycopy(cs,0,newElements,len,cs.length);

setArray(newElements);

}

return true;

}finally{

lock.unlock();

}

}

/**

* Inserts all of the elements in the specified collection into this

* list, starting at the specified position.  Shifts the element

* currently at that position (if any) and any subsequent elements to

* the right (increases their indices).  The new elements will appear

* in this list in the order that they are returned by the

* specified collection's iterator.

*

*@paramindexindex at which to insert the first element

*        from the specified collection

*@paramccollection containing elements to be added to this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsIndexOutOfBoundsException {@inheritDoc}

*@throwsNullPointerException if the specified collection is null

*@see#add(int,Object)

*/

public booleanaddAll(intindex,Collection c) {

Object[] cs = c.toArray();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(index > len || index <0)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+len);

if(cs.length==0)

return false;

intnumMoved = len - index;

Object[] newElements;

if(numMoved ==0)

newElements = Arrays.copyOf(elements,len + cs.length);

else{

newElements =newObject[len + cs.length];

System.arraycopy(elements,0,newElements,0,index);

System.arraycopy(elements,index,

newElements,index + cs.length,

numMoved);

}

System.arraycopy(cs,0,newElements,index,cs.length);

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

public voidforEach(Consumer action) {

if(action ==null)throw newNullPointerException();

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

action.accept(e);

}

}

public booleanremoveIf(Predicate filter) {

if(filter ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

if(!filter.test(e))

temp[newlen++] = e;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

public voidreplaceAll(UnaryOperator operator) {

if(operator ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len);

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

newElements[i] = operator.apply(e);

}

setArray(newElements);

}finally{

lock.unlock();

}

}

public voidsort(Comparator c) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

Object[] newElements = Arrays.copyOf(elements,elements.length);

@SuppressWarnings("unchecked")E[] es = (E[])newElements;

Arrays.sort(es,c);

setArray(newElements);

}finally{

lock.unlock();

}

}

/**

* Saves this list to a stream (that is, serializes it).

*

*@paramsthe stream

*@throwsjava.io.IOException if an I/O error occurs

*@serialDataThe length of the array backing the list is emitted

*              (int), followed by all of its elements (each an Object)

*              in the proper order.

*/

private voidwriteObject(java.io.ObjectOutputStream s)

throwsjava.io.IOException {

s.defaultWriteObject();

Object[] elements = getArray();

// Write out array length

s.writeInt(elements.length);

// Write out all elements in the proper order.

for(Object element : elements)

s.writeObject(element);

}

/**

* Reconstitutes this list from a stream (that is, deserializes it).

*@paramsthe stream

*@throwsClassNotFoundException if the class of a serialized object

*        could not be found

*@throwsjava.io.IOException if an I/O error occurs

*/

private voidreadObject(java.io.ObjectInputStream s)

throwsjava.io.IOException,ClassNotFoundException {

s.defaultReadObject();

// bind to new lock

resetLock();

// Read in array length and allocate array

intlen = s.readInt();

Object[] elements =newObject[len];

// Read in all elements in the proper order.

for(inti =0;i < len;i++)

elements[i] = s.readObject();

setArray(elements);

}

/**

* Returns a string representation of this list.  The string

* representation consists of the string representations of the list's

* elements in the order they are returned by its iterator, enclosed in

* square brackets ({@code"[]"}).  Adjacent elements are separated by

* the characters {@code", "} (comma and space).  Elements are

* converted to strings as by {@linkString#valueOf(Object)}.

*

*@returna string representation of this list

*/

publicStringtoString() {

returnArrays.toString(getArray());

}

/**

* Compares the specified object with this list for equality.

* Returns {@codetrue} if the specified object is the same object

* as this object, or if it is also a {@linkList} and the sequence

* of elements returned by an {@linkplainList#iterator() iterator}

* over the specified list is the same as the sequence returned by

* an iterator over this list.  The two sequences are considered to

* be the same if they have the same length and corresponding

* elements at the same position in the sequence areequal.

* Two elements {@codee1} and {@codee2} are considered

*equalif {@code(e1==null ? e2==null : e1.equals(e2))}.

*

*@paramothe object to be compared for equality with this list

*@return{@codetrue} if the specified object is equal to this list

*/

public booleanequals(Object o) {

if(o ==this)

return true;

if(!(oinstanceofList))

return false;

List list = (List)(o);

Iterator it = list.iterator();

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i)

if(!it.hasNext() || !eq(elements[i],it.next()))

return false;

if(it.hasNext())

return false;

return true;

}

/**

* Returns the hash code value for this list.

*

*

This implementation uses the definition in {@linkList#hashCode}.

*

*@returnthe hash code value for this list

*/

public inthashCode() {

inthashCode =1;

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i) {

Object obj = elements[i];

hashCode =31*hashCode + (obj==null?0: obj.hashCode());

}

returnhashCode;

}

/**

* Returns an iterator over the elements in this list in proper sequence.

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove} method.

*

*@returnan iterator over the elements in this list in proper sequence

*/

publicIteratoriterator() {

return newCOWIterator(getArray(),0);

}

/**

* {@inheritDoc}

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove}, {@codeset} or {@codeadd} methods.

*/

publicListIteratorlistIterator() {

return newCOWIterator(getArray(),0);

}

/**

* {@inheritDoc}

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove}, {@codeset} or {@codeadd} methods.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicListIteratorlistIterator(intindex) {

Object[] elements = getArray();

intlen = elements.length;

if(index <0|| index > len)

throw newIndexOutOfBoundsException("Index: "+index);

return newCOWIterator(elements,index);

}

/**

* Returns a {@linkSpliterator} over the elements in this list.

*

*

The {@codeSpliterator} reports {@linkSpliterator#IMMUTABLE},

* {@linkSpliterator#ORDERED}, {@linkSpliterator#SIZED}, and

* {@linkSpliterator#SUBSIZED}.

*

*

The spliterator provides a snapshot of the state of the list

* when the spliterator was constructed. No synchronization is needed while

* operating on the spliterator.

*

*@returna {@codeSpliterator} over the elements in this list

*@since1.8

*/

publicSpliteratorspliterator() {

returnSpliterators.spliterator

(getArray(),Spliterator.IMMUTABLE| Spliterator.ORDERED);

}

static final classCOWIteratorimplementsListIterator {

/** Snapshot of the array */

private finalObject[]snapshot;

/** Index of element to be returned by subsequent call to next.  */

private intcursor;

privateCOWIterator(Object[] elements, intinitialCursor) {

cursor= initialCursor;

snapshot= elements;

}

public booleanhasNext() {

returncursor

}

public booleanhasPrevious() {

returncursor>0;

}

@SuppressWarnings("unchecked")

publicEnext() {

if(! hasNext())

throw newNoSuchElementException();

return(E)snapshot[cursor++];

}

@SuppressWarnings("unchecked")

publicEprevious() {

if(! hasPrevious())

throw newNoSuchElementException();

return(E)snapshot[--cursor];

}

public intnextIndex() {

returncursor;

}

public intpreviousIndex() {

returncursor-1;

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@coderemove}

*        is not supported by this iterator.

*/

public voidremove() {

throw newUnsupportedOperationException();

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@codeset}

*        is not supported by this iterator.

*/

public voidset(Ee) {

throw newUnsupportedOperationException();

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@codeadd}

*        is not supported by this iterator.

*/

public voidadd(Ee) {

throw newUnsupportedOperationException();

}

@Override

public voidforEachRemaining(Consumer action) {

Objects.requireNonNull(action);

Object[] elements =snapshot;

final intsize = elements.length;

for(inti =cursor;i < size;i++) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

action.accept(e);

}

cursor= size;

}

}

/**

* Returns a view of the portion of this list between

* {@codefromIndex}, inclusive, and {@codetoIndex}, exclusive.

* The returned list is backed by this list, so changes in the

* returned list are reflected in this list.

*

*

The semantics of the list returned by this method become

* undefined if the backing list (i.e., this list) is modified in

* any way other than via the returned list.

*

*@paramfromIndexlow endpoint (inclusive) of the subList

*@paramtoIndexhigh endpoint (exclusive) of the subList

*@returna view of the specified range within this list

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicListsubList(intfromIndex, inttoIndex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(fromIndex <0|| toIndex > len || fromIndex > toIndex)

throw newIndexOutOfBoundsException();

return newCOWSubList(this,fromIndex,toIndex);

}finally{

lock.unlock();

}

}

/**

* Sublist for CopyOnWriteArrayList.

* This class extends AbstractList merely for convenience, to

* avoid having to define addAll, etc. This doesn't hurt, but

* is wasteful.  This class does not need or use modCount

* mechanics in AbstractList, but does need to check for

* concurrent modification using similar mechanics.  On each

* operation, the array that we expect the backing list to use

* is checked and updated.  Since we do this for all of the

* base operations invoked by those defined in AbstractList,

* all is well.  While inefficient, this is not worth

* improving.  The kinds of list operations inherited from

* AbstractList are already so slow on COW sublists that

* adding a bit more space/time doesn't seem even noticeable.

*/

private static classCOWSubList

extendsAbstractList

implementsRandomAccess

{

private finalCopyOnWriteArrayListl;

private final intoffset;

private intsize;

privateObject[]expectedArray;

// only call this holding l's lock

COWSubList(CopyOnWriteArrayList list,

intfromIndex, inttoIndex) {

l= list;

expectedArray=l.getArray();

offset= fromIndex;

size= toIndex - fromIndex;

}

// only call this holding l's lock

private voidcheckForComodification() {

if(l.getArray() !=expectedArray)

throw newConcurrentModificationException();

}

// only call this holding l's lock

private voidrangeCheck(intindex) {

if(index <0|| index >=size)

throw newIndexOutOfBoundsException("Index: "+index+

",Size: "+size);

}

publicEset(intindex,Eelement) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

Ex =l.set(index+offset,element);

expectedArray=l.getArray();

returnx;

}finally{

lock.unlock();

}

}

publicEget(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

returnl.get(index+offset);

}finally{

lock.unlock();

}

}

public intsize() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

returnsize;

}finally{

lock.unlock();

}

}

public voidadd(intindex,Eelement) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(index <0|| index >size)

throw newIndexOutOfBoundsException();

l.add(index+offset,element);

expectedArray=l.getArray();

size++;

}finally{

lock.unlock();

}

}

public voidclear() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

l.removeRange(offset,offset+size);

expectedArray=l.getArray();

size=0;

}finally{

lock.unlock();

}

}

publicEremove(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

Eresult =l.remove(index+offset);

expectedArray=l.getArray();

size--;

returnresult;

}finally{

lock.unlock();

}

}

public booleanremove(Object o) {

intindex = indexOf(o);

if(index == -1)

return false;

remove(index);

return true;

}

publicIteratoriterator() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

return newCOWSubListIterator(l,0,offset,size);

}finally{

lock.unlock();

}

}

publicListIteratorlistIterator(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(index <0|| index >size)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+size);

return newCOWSubListIterator(l,index,offset,size);

}finally{

lock.unlock();

}

}

publicListsubList(intfromIndex, inttoIndex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(fromIndex <0|| toIndex >size|| fromIndex > toIndex)

throw newIndexOutOfBoundsException();

return newCOWSubList(l,fromIndex +offset,

toIndex +offset);

}finally{

lock.unlock();

}

}

public voidforEach(Consumer action) {

if(action ==null)throw newNullPointerException();

intlo =offset;

inthi =offset+size;

Object[] a =expectedArray;

if(l.getArray() != a)

throw newConcurrentModificationException();

if(lo <0|| hi > a.length)

throw newIndexOutOfBoundsException();

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) a[i];

action.accept(e);

}

}

public voidreplaceAll(UnaryOperator operator) {

if(operator ==null)throw newNullPointerException();

finalReentrantLock lock =l.lock;

lock.lock();

try{

intlo =offset;

inthi =offset+size;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

Object[] newElements = Arrays.copyOf(elements,len);

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

newElements[i] = operator.apply(e);

}

l.setArray(expectedArray= newElements);

}finally{

lock.unlock();

}

}

public voidsort(Comparator c) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

intlo =offset;

inthi =offset+size;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

Object[] newElements = Arrays.copyOf(elements,len);

@SuppressWarnings("unchecked")E[] es = (E[])newElements;

Arrays.sort(es,lo,hi,c);

l.setArray(expectedArray= newElements);

}finally{

lock.unlock();

}

}

public booleanremoveAll(Collection c) {

if(c ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

Object element = elements[i];

if(!c.contains(element))

temp[newSize++] = element;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

public booleanretainAll(Collection c) {

if(c ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

Object element = elements[i];

if(c.contains(element))

temp[newSize++] = element;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

public booleanremoveIf(Predicate filter) {

if(filter ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

if(!filter.test(e))

temp[newSize++] = e;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

publicSpliteratorspliterator() {

intlo =offset;

inthi =offset+size;

Object[] a =expectedArray;

if(l.getArray() != a)

throw newConcurrentModificationException();

if(lo <0|| hi > a.length)

throw newIndexOutOfBoundsException();

returnSpliterators.spliterator

(a,lo,hi,Spliterator.IMMUTABLE| Spliterator.ORDERED);

}

}

private static classCOWSubListIteratorimplementsListIterator {

private finalListIteratorit;

private final intoffset;

private final intsize;

COWSubListIterator(List l, intindex, intoffset, intsize) {

this.offset= offset;

this.size= size;

it= l.listIterator(index+offset);

}

public booleanhasNext() {

returnnextIndex()

}

publicEnext() {

if(hasNext())

returnit.next();

else

throw newNoSuchElementException();

}

public booleanhasPrevious() {

returnpreviousIndex() >=0;

}

publicEprevious() {

if(hasPrevious())

returnit.previous();

else

throw newNoSuchElementException();

}

public intnextIndex() {

returnit.nextIndex() -offset;

}

public intpreviousIndex() {

returnit.previousIndex() -offset;

}

public voidremove() {

throw newUnsupportedOperationException();

}

public voidset(Ee) {

throw newUnsupportedOperationException();

}

public voidadd(Ee) {

throw newUnsupportedOperationException();

}

@Override

public voidforEachRemaining(Consumer action) {

Objects.requireNonNull(action);

ints =size;

ListIterator i =it;

while(nextIndex() < s) {

action.accept(i.next());

}

}

}

// Support for resetting lock while deserializing

private voidresetLock() {

UNSAFE.putObjectVolatile(this,lockOffset, newReentrantLock());

}

private static finalsun.misc.UnsafeUNSAFE;

private static final longlockOffset;

static{

try{

UNSAFE= sun.misc.Unsafe.getUnsafe();

Class k = CopyOnWriteArrayList.class;

lockOffset=UNSAFE.objectFieldOffset

(k.getDeclaredField("lock"));

}catch(Exception e) {

throw newError(e);

}

}

}

```

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容