--- old/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java 2012-12-10 13:27:30.294690019 -0800 +++ new/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java 2012-12-10 13:27:30.126690013 -0800 @@ -36,6 +36,9 @@ package java.util.concurrent; import java.util.*; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Block; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; /** * A thread-safe variant of {@link java.util.ArrayList} in which all mutative @@ -1317,6 +1320,92 @@ } } + @SuppressWarnings("unchecked") + public void forEach(Block block) { + Objects.requireNonNull(block); + final Object[] elements = getArray(); + for (final Object element : elements) { + block.accept((E) element); + } + } + + @Override + public void sort(Comparator c) { + Objects.requireNonNull(c); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + @SuppressWarnings("unchecked") + final E[] elements = (E[]) getArray(); + final E[] newElements = Arrays.copyOf(elements, elements.length); + Arrays.sort(newElements, c); + setArray(newElements); + } finally { + lock.unlock(); + } + } + + @Override + public boolean removeAll(Predicate filter) { + Objects.requireNonNull(filter); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + @SuppressWarnings("unchecked") + final E[] elements = (E[]) getArray(); + final int size = elements.length; + + // figure out which elements are to be removed + // any exception thrown from the filter predicate at this stage + // will leave the collection unmodified + int removeCount = 0; + final BitSet removeSet = new BitSet(size); + for (int i=0; i < size; i++) { + final E element = elements[i]; + if (filter.test(element)) { + removeSet.set(i); + removeCount++; + } + } + + // copy surviving elements into a new array + final boolean anyToRemove = removeCount > 0; + if (anyToRemove) { + final int newSize = size - removeCount; + final Object[] newElements = new Object[newSize]; + for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { + i = removeSet.nextClearBit(i); + newElements[j] = elements[i]; + } + setArray(newElements); + } + + return anyToRemove; + } finally { + lock.unlock(); + } + } + + @Override + public void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + @SuppressWarnings("unchecked") + final E[] elements = (E[]) getArray(); + final int len = elements.length; + @SuppressWarnings("unchecked") + final E[] newElements = (E[]) new Object[len]; + for (int i=0; i < len; i++) { + newElements[i] = operator.operate(elements[i]); + } + setArray(newElements); + } finally { + lock.unlock(); + } + } + // Support for resetting lock while deserializing private void resetLock() { UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());