Merge TP1A.211018.001

Change-Id: Iaab673e0cf2e34f5c7098eb87f2530b052b772e2
diff --git a/api/current.txt b/api/current.txt
index 604b708..416cc76 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -1307,6 +1307,8 @@
     method public int available();
     method public int read();
     method public int read(byte[], int, int);
+    method public byte[] readAllBytes();
+    method public int readNBytes(byte[], int, int);
     method public void reset();
     method public long skip(long);
     field protected byte[] buf;
@@ -1322,9 +1324,11 @@
     method public int size();
     method @NonNull public byte[] toByteArray();
     method @NonNull public String toString(@NonNull String) throws java.io.UnsupportedEncodingException;
+    method @NonNull public String toString(@NonNull java.nio.charset.Charset);
     method @Deprecated @NonNull public String toString(int);
     method public void write(int);
     method public void write(@NonNull byte[], int, int);
+    method public void writeBytes(byte[]);
     method public void writeTo(@NonNull java.io.OutputStream) throws java.io.IOException;
     field @NonNull protected byte[] buf;
     field protected int count;
@@ -1635,11 +1639,16 @@
     method public void close() throws java.io.IOException;
     method public void mark(int);
     method public boolean markSupported();
+    method public static java.io.InputStream nullInputStream();
     method public abstract int read() throws java.io.IOException;
     method public int read(byte[]) throws java.io.IOException;
     method public int read(byte[], int, int) throws java.io.IOException;
+    method public byte[] readAllBytes() throws java.io.IOException;
+    method public byte[] readNBytes(int) throws java.io.IOException;
+    method public int readNBytes(byte[], int, int) throws java.io.IOException;
     method public void reset() throws java.io.IOException;
     method public long skip(long) throws java.io.IOException;
+    method public long transferTo(java.io.OutputStream) throws java.io.IOException;
   }
 
   public class InputStreamReader extends java.io.Reader {
@@ -1876,6 +1885,7 @@
     ctor public OutputStream();
     method public void close() throws java.io.IOException;
     method public void flush() throws java.io.IOException;
+    method public static java.io.OutputStream nullOutputStream();
     method public abstract void write(int) throws java.io.IOException;
     method public void write(byte[]) throws java.io.IOException;
     method public void write(byte[], int, int) throws java.io.IOException;
@@ -14223,7 +14233,6 @@
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -14464,7 +14473,7 @@
     method public final boolean isEmpty();
     method @NonNull public java.util.Iterator<K> iterator();
     method public boolean remove(@NonNull Object);
-    method public boolean removeAll(@NonNull java.util.Collection<?>);
+    method public final boolean removeAll(@NonNull java.util.Collection<?>);
     method public final boolean retainAll(@NonNull java.util.Collection<?>);
     method public final int size();
     method @NonNull public java.util.Spliterator<K> spliterator();
@@ -14480,7 +14489,6 @@
     method public void addLast(E);
     method public java.util.Iterator<E> descendingIterator();
     method public E element();
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public E getFirst();
     method public E getLast();
     method public java.util.Iterator<E> iterator();
@@ -14506,7 +14514,6 @@
   public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue<E> implements java.util.Queue<E> java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public E peek();
@@ -14796,7 +14803,6 @@
     ctor public ForkJoinPool();
     ctor public ForkJoinPool(int);
     ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
-    ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean, int, int, int, java.util.function.Predicate<? super java.util.concurrent.ForkJoinPool>, long, java.util.concurrent.TimeUnit);
     method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public static java.util.concurrent.ForkJoinPool commonPool();
@@ -14923,7 +14929,6 @@
     method public java.util.Iterator<E> descendingIterator();
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public E getFirst();
     method public E getLast();
     method public java.util.Iterator<E> iterator();
@@ -14964,7 +14969,6 @@
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public boolean offer(E);
@@ -14982,7 +14986,6 @@
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public int getWaitingConsumerCount();
     method public boolean hasWaitingConsumer();
     method public java.util.Iterator<E> iterator();
@@ -15032,7 +15035,6 @@
     method public java.util.Comparator<? super E> comparator();
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
-    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public boolean offer(E, long, java.util.concurrent.TimeUnit);
@@ -15130,29 +15132,6 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
-  public class SubmissionPublisher<T> implements java.lang.AutoCloseable java.util.concurrent.Flow.Publisher<T> {
-    ctor public SubmissionPublisher(java.util.concurrent.Executor, int, java.util.function.BiConsumer<? super java.util.concurrent.Flow.Subscriber<? super T>,? super java.lang.Throwable>);
-    ctor public SubmissionPublisher(java.util.concurrent.Executor, int);
-    ctor public SubmissionPublisher();
-    method public void close();
-    method public void closeExceptionally(Throwable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> consume(java.util.function.Consumer<? super T>);
-    method public int estimateMaximumLag();
-    method public long estimateMinimumDemand();
-    method public Throwable getClosedException();
-    method public java.util.concurrent.Executor getExecutor();
-    method public int getMaxBufferCapacity();
-    method public int getNumberOfSubscribers();
-    method public java.util.List<java.util.concurrent.Flow.Subscriber<? super T>> getSubscribers();
-    method public boolean hasSubscribers();
-    method public boolean isClosed();
-    method public boolean isSubscribed(java.util.concurrent.Flow.Subscriber<? super T>);
-    method public int offer(T, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
-    method public int offer(T, long, java.util.concurrent.TimeUnit, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
-    method public int submit(T);
-    method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>);
-  }
-
   public class SynchronousQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
@@ -15194,7 +15173,7 @@
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method protected void beforeExecute(Thread, Runnable);
     method public void execute(Runnable);
-    method @Deprecated protected void finalize();
+    method protected void finalize();
     method public int getActiveCount();
     method public long getCompletedTaskCount();
     method public int getCorePoolSize();
@@ -15245,12 +15224,9 @@
 
   public enum TimeUnit {
     method public long convert(long, java.util.concurrent.TimeUnit);
-    method public long convert(java.time.Duration);
-    method public static java.util.concurrent.TimeUnit of(java.time.temporal.ChronoUnit);
     method public void sleep(long) throws java.lang.InterruptedException;
     method public void timedJoin(Thread, long) throws java.lang.InterruptedException;
     method public void timedWait(Object, long) throws java.lang.InterruptedException;
-    method public java.time.temporal.ChronoUnit toChronoUnit();
     method public long toDays(long);
     method public long toHours(long);
     method public long toMicros(long);
diff --git a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
index 53e0398..28517aa 100644
--- a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
@@ -147,7 +147,7 @@
         assertFalse(f.isCancelled());
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
     }
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -202,7 +202,7 @@
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
         assertTrue(f.isCancelled());
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
     }
 
     /**
@@ -349,12 +349,12 @@
 
         f = new CompletableFuture<String>();
         assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
 
         for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
             f = new CompletableFuture<String>();
             assertTrue(f.cancel(mayInterruptIfRunning));
-            assertTrue(f.toString().contains("[Completed exceptionally:"));
+            assertTrue(f.toString().contains("[Completed exceptionally]"));
         }
     }
 
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
index 194dd58..e763ae4 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -834,7 +834,9 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        // Android-changed: Use a longer delay to ensure task does not expire
+        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
index 81f7370..8f65c84 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -783,7 +783,9 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        // Android-changed: Use a longer delay to ensure task does not expire
+        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
deleted file mode 100644
index 12ec722..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ArrayBlockingQueueTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(capacity);
-        for (int i = 0; i < capacity; ++i) {
-            queue.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        queue.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
deleted file mode 100644
index 6a6f7ea..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ConcurrentLinkedDequeTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
-        for (int i = 0; i < capacity; ++i) {
-            deque.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        deque.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
deleted file mode 100644
index 6a1bffa..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ConcurrentLinkedQueueTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
-        for (int i = 0; i < capacity; ++i) {
-            queue.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        queue.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
index 48d4170..578970e 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
@@ -70,94 +70,4 @@
             fail("Unexpected exception: " + t.getMessage());
         }
     }
-
-    @Test
-    public void testConstructor_withKeepAliveTime() {
-
-        try {
-            ForkJoinPool pool = new ForkJoinPool(0,
-                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
-                    /*handler*/ null,
-                    /*asyncMode*/ false,
-                    /*corePoolSize*/ 10,
-                    /*maximumPoolSize*/ 10,
-                    /*minimumRunnable*/ 1,
-                    /*saturate*/ null,
-                    /*keepAliveTime*/ 60,
-                    /*unit*/ TimeUnit.SECONDS);
-            fail("Expected IllegalArgumentException when parallelism is 0");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            ForkJoinPool pool = new ForkJoinPool(-1,
-                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
-                    /*handler*/ null,
-                    /*asyncMode*/ false,
-                    /*corePoolSize*/ 10,
-                    /*maximumPoolSize*/ 10,
-                    /*minimumRunnable*/ 1,
-                    /*saturate*/ null,
-                    /*keepAliveTime*/ 60,
-                    /*unit*/ TimeUnit.SECONDS);
-            fail("Expected IllegalArgumentException when parallelism is less than 0");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            ForkJoinPool pool = new ForkJoinPool(8,
-                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
-                    /*handler*/ null,
-                    /*asyncMode*/ false,
-                    /*corePoolSize*/ 10,
-                    /*maximumPoolSize*/ 5,
-                    /*minimumRunnable*/ 1,
-                    /*saturate*/ null,
-                    /*keepAliveTime*/ 60,
-                    /*unit*/ TimeUnit.SECONDS);
-            fail("Expected IllegalArgumentException when maximumPoolSize is less than parallelism");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            ForkJoinPool pool = new ForkJoinPool(8,
-                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
-                    /*handler*/ null,
-                    /*asyncMode*/ false,
-                    /*corePoolSize*/ 10,
-                    /*maximumPoolSize*/ 10,
-                    /*minimumRunnable*/ 1,
-                    /*saturate*/ null,
-                    /*keepAliveTime*/ 0,
-                    /*unit*/ TimeUnit.SECONDS);
-            fail("Expected IllegalArgumentException when keepAlivetime is 0");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            ForkJoinPool pool = new ForkJoinPool(8,
-                    null,
-                    /*handler*/ null,
-                    /*asyncMode*/ false,
-                    /*corePoolSize*/ 10,
-                    /*maximumPoolSize*/ 10,
-                    /*minimumRunnable*/ 1,
-                    /*saturate*/ null,
-                    /*keepAliveTime*/ 60,
-                    /*unit*/ TimeUnit.SECONDS);
-            fail("Expected NullPointerException when factory is null");
-        } catch (NullPointerException e) {
-        }
-
-        ForkJoinPool pool = new ForkJoinPool(8,
-                ForkJoinPool.defaultForkJoinWorkerThreadFactory,
-                /*handler*/ null,
-                /*asyncMode*/ false,
-                /*corePoolSize*/ 10,
-                /*maximumPoolSize*/ 10,
-                /*minimumRunnable*/ 1,
-                /*saturate*/ null,
-                /*keepAliveTime*/ 60,
-                /*unit*/ TimeUnit.SECONDS);
-    }
 }
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
deleted file mode 100644
index 66dd942..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class LinkedBlockingDequeTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>();
-        for (int i = 0; i < capacity; ++i) {
-            deque.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        deque.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
deleted file mode 100644
index 4363988..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class LinkedBlockingQueueTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
-        for (int i = 0; i < capacity; ++i) {
-            queue.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        queue.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
deleted file mode 100644
index 5b09284..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.LinkedTransferQueue;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class LinkedTransferQueueTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();
-        for (int i = 0; i < capacity; ++i) {
-            queue.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        queue.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
deleted file mode 100644
index ba7bc0c..0000000
--- a/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.java.util.concurrent;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.atomic.LongAdder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class PriorityBlockingQueueTest {
-
-    @Test
-    public void testForEach() {
-        int capacity = 10;
-        PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>(capacity);
-        for (int i = 0; i < capacity; ++i) {
-            queue.add(Integer.valueOf(i+1));
-        }
-        LongAdder adder = new LongAdder();
-        queue.forEach((Integer x) -> adder.add(x.longValue()));
-        // The size is small enough for the sum not to overflow
-        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
-    }
-}
diff --git a/ojluni/annotations/sdk/nullability/java/io/ByteArrayOutputStream.annotated.java b/ojluni/annotations/sdk/nullability/java/io/ByteArrayOutputStream.annotated.java
index 3fdca11..a642f85 100644
--- a/ojluni/annotations/sdk/nullability/java/io/ByteArrayOutputStream.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/io/ByteArrayOutputStream.annotated.java
@@ -50,6 +50,8 @@
 
 @libcore.util.NonNull public synchronized java.lang.String toString(@libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
 
+@libcore.util.NonNull public synchronized java.lang.String toString(@libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
 @Deprecated
 @libcore.util.NonNull public synchronized java.lang.String toString(int hibyte) { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/src/main/java/java/io/BufferedOutputStream.java b/ojluni/src/main/java/java/io/BufferedOutputStream.java
index 0579704..f114485 100644
--- a/ojluni/src/main/java/java/io/BufferedOutputStream.java
+++ b/ojluni/src/main/java/java/io/BufferedOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,10 +32,9 @@
  * system for each byte written.
  *
  * @author  Arthur van Hoff
- * @since   JDK1.0
+ * @since   1.0
  */
-public
-class BufferedOutputStream extends FilterOutputStream {
+public class BufferedOutputStream extends FilterOutputStream {
     /**
      * The internal buffer where data is stored.
      */
@@ -43,8 +42,8 @@
 
     /**
      * The number of valid bytes in the buffer. This value is always
-     * in the range <tt>0</tt> through <tt>buf.length</tt>; elements
-     * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
+     * in the range {@code 0} through {@code buf.length}; elements
+     * {@code buf[0]} through {@code buf[count-1]} contain valid
      * byte data.
      */
     protected int count;
@@ -90,6 +89,7 @@
      * @param      b   the byte to be written.
      * @exception  IOException  if an I/O error occurs.
      */
+    @Override
     public synchronized void write(int b) throws IOException {
         if (count >= buf.length) {
             flushBuffer();
diff --git a/ojluni/src/main/java/java/io/BufferedReader.java b/ojluni/src/main/java/java/io/BufferedReader.java
index fb814b1..20a240a 100644
--- a/ojluni/src/main/java/java/io/BufferedReader.java
+++ b/ojluni/src/main/java/java/io/BufferedReader.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,7 +65,7 @@
  * @see java.nio.file.Files#newBufferedReader
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class BufferedReader extends Reader {
@@ -283,6 +283,7 @@
      *             stream has been reached
      *
      * @exception  IOException  If an I/O error occurs
+     * @exception  IndexOutOfBoundsException {@inheritDoc}
      */
     public int read(char cbuf[], int off, int len) throws IOException {
         synchronized (lock) {
@@ -307,14 +308,15 @@
 
     /**
      * Reads a line of text.  A line is considered to be terminated by any one
-     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
-     * followed immediately by a linefeed.
+     * of a line feed ('\n'), a carriage return ('\r'), a carriage return
+     * followed immediately by a line feed, or by reaching the end-of-file
+     * (EOF).
      *
      * @param      ignoreLF  If true, the next '\n' will be skipped
      *
      * @return     A String containing the contents of the line, not including
      *             any line-termination characters, or null if the end of the
-     *             stream has been reached
+     *             stream has been reached without reading any characters
      *
      * @see        java.io.LineNumberReader#readLine()
      *
@@ -385,12 +387,13 @@
 
     /**
      * Reads a line of text.  A line is considered to be terminated by any one
-     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
-     * followed immediately by a linefeed.
+     * of a line feed ('\n'), a carriage return ('\r'), a carriage return
+     * followed immediately by a line feed, or by reaching the end-of-file
+     * (EOF).
      *
      * @return     A String containing the contents of the line, not including
      *             any line-termination characters, or null if the end of the
-     *             stream has been reached
+     *             stream has been reached without reading any characters
      *
      * @exception  IOException  If an I/O error occurs
      *
@@ -570,7 +573,7 @@
      * @since 1.8
      */
     public Stream<String> lines() {
-        Iterator<String> iter = new Iterator<String>() {
+        Iterator<String> iter = new Iterator<>() {
             String nextLine = null;
 
             @Override
diff --git a/ojluni/src/main/java/java/io/BufferedWriter.java b/ojluni/src/main/java/java/io/BufferedWriter.java
index a5d810a..3d8e1ee 100644
--- a/ojluni/src/main/java/java/io/BufferedWriter.java
+++ b/ojluni/src/main/java/java/io/BufferedWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
  * The default is large enough for most purposes.
  *
  * <p> A newLine() method is provided, which uses the platform's own notion of
- * line separator as defined by the system property <tt>line.separator</tt>.
+ * line separator as defined by the system property {@code line.separator}.
  * Not all platforms use the newline character ('\n') to terminate lines.
  * Calling this method to terminate each output line is therefore preferred to
  * writing a newline character directly.
@@ -60,7 +60,7 @@
  * @see java.nio.file.Files#newBufferedWriter
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class BufferedWriter extends Writer {
@@ -73,12 +73,6 @@
     private static int defaultCharBufferSize = 8192;
 
     /**
-     * Line separator string.  This is the value of the line.separator
-     * property at the moment that the stream was created.
-     */
-    private String lineSeparator;
-
-    /**
      * Creates a buffered character-output stream that uses a default-sized
      * output buffer.
      *
@@ -105,9 +99,6 @@
         cb = new char[sz];
         nChars = sz;
         nextChar = 0;
-
-        lineSeparator = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("line.separator"));
     }
 
     /** Checks to make sure that the stream has not been closed */
@@ -162,13 +153,18 @@
      * needed.  If the requested length is at least as large as the buffer,
      * however, then this method will flush the buffer and write the characters
      * directly to the underlying stream.  Thus redundant
-     * <code>BufferedWriter</code>s will not copy data unnecessarily.
+     * {@code BufferedWriter}s will not copy data unnecessarily.
      *
      * @param  cbuf  A character array
      * @param  off   Offset from which to start reading characters
      * @param  len   Number of characters to write
      *
-     * @exception  IOException  If an I/O error occurs
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given array
+     *
+     * @throws  IOException  If an I/O error occurs
      */
     public void write(char cbuf[], int off, int len) throws IOException {
         synchronized (lock) {
@@ -204,17 +200,24 @@
     /**
      * Writes a portion of a String.
      *
-     * <p> If the value of the <tt>len</tt> parameter is negative then no
-     * characters are written.  This is contrary to the specification of this
-     * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
-     * superclass}, which requires that an {@link IndexOutOfBoundsException} be
-     * thrown.
+     * @implSpec
+     * While the specification of this method in the
+     * {@linkplain java.io.Writer#write(java.lang.String,int,int) superclass}
+     * recommends that an {@link IndexOutOfBoundsException} be thrown
+     * if {@code len} is negative or {@code off + len} is negative,
+     * the implementation in this class does not throw such an exception in
+     * these cases but instead simply writes no characters.
      *
      * @param  s     String to be written
      * @param  off   Offset from which to start reading characters
      * @param  len   Number of characters to be written
      *
-     * @exception  IOException  If an I/O error occurs
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative,
+     *          or {@code off + len} is greater than the length
+     *          of the given string
+     *
+     * @throws  IOException  If an I/O error occurs
      */
     public void write(String s, int off, int len) throws IOException {
         synchronized (lock) {
@@ -234,13 +237,13 @@
 
     /**
      * Writes a line separator.  The line separator string is defined by the
-     * system property <tt>line.separator</tt>, and is not necessarily a single
+     * system property {@code line.separator}, and is not necessarily a single
      * newline ('\n') character.
      *
      * @exception  IOException  If an I/O error occurs
      */
     public void newLine() throws IOException {
-        write(lineSeparator);
+        write(System.lineSeparator());
     }
 
     /**
diff --git a/ojluni/src/main/java/java/io/ByteArrayInputStream.java b/ojluni/src/main/java/java/io/ByteArrayInputStream.java
index d07f074..cb20f8c 100644
--- a/ojluni/src/main/java/java/io/ByteArrayInputStream.java
+++ b/ojluni/src/main/java/java/io/ByteArrayInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,30 +25,32 @@
 
 package java.io;
 
+import java.util.Arrays;
+import java.util.Objects;
+
 /**
- * A <code>ByteArrayInputStream</code> contains
+ * A {@code ByteArrayInputStream} contains
  * an internal buffer that contains bytes that
  * may be read from the stream. An internal
  * counter keeps track of the next byte to
- * be supplied by the <code>read</code> method.
+ * be supplied by the {@code read} method.
  * <p>
- * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+ * Closing a {@code ByteArrayInputStream} has no effect. The methods in
  * this class can be called after the stream has been closed without
- * generating an <tt>IOException</tt>.
+ * generating an {@code IOException}.
  *
  * @author  Arthur van Hoff
  * @see     java.io.StringBufferInputStream
- * @since   JDK1.0
+ * @since   1.0
  */
-public
-class ByteArrayInputStream extends InputStream {
+public class ByteArrayInputStream extends InputStream {
 
     /**
      * An array of bytes that was provided
-     * by the creator of the stream. Elements <code>buf[0]</code>
-     * through <code>buf[count-1]</code> are the
+     * by the creator of the stream. Elements {@code buf[0]}
+     * through {@code buf[count-1]} are the
      * only bytes that can ever be read from the
-     * stream;  element <code>buf[pos]</code> is
+     * stream;  element {@code buf[pos]} is
      * the next byte to be read.
      */
     protected byte buf[];
@@ -56,9 +58,9 @@
     /**
      * The index of the next character to read from the input stream buffer.
      * This value should always be nonnegative
-     * and not larger than the value of <code>count</code>.
+     * and not larger than the value of {@code count}.
      * The next byte to be read from the input stream buffer
-     * will be <code>buf[pos]</code>.
+     * will be {@code buf[pos]}.
      */
     protected int pos;
 
@@ -66,14 +68,14 @@
      * The currently marked position in the stream.
      * ByteArrayInputStream objects are marked at position zero by
      * default when constructed.  They may be marked at another
-     * position within the buffer by the <code>mark()</code> method.
+     * position within the buffer by the {@code mark()} method.
      * The current buffer position is set to this point by the
-     * <code>reset()</code> method.
+     * {@code reset()} method.
      * <p>
      * If no mark has been set, then the value of mark is the offset
      * passed to the constructor (or 0 if the offset was not supplied).
      *
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected int mark = 0;
 
@@ -81,22 +83,22 @@
      * The index one greater than the last valid character in the input
      * stream buffer.
      * This value should always be nonnegative
-     * and not larger than the length of <code>buf</code>.
+     * and not larger than the length of {@code buf}.
      * It  is one greater than the position of
-     * the last byte within <code>buf</code> that
+     * the last byte within {@code buf} that
      * can ever be read  from the input stream buffer.
      */
     protected int count;
 
     /**
-     * Creates a <code>ByteArrayInputStream</code>
-     * so that it  uses <code>buf</code> as its
+     * Creates a {@code ByteArrayInputStream}
+     * so that it  uses {@code buf} as its
      * buffer array.
      * The buffer array is not copied.
-     * The initial value of <code>pos</code>
-     * is <code>0</code> and the initial value
-     * of  <code>count</code> is the length of
-     * <code>buf</code>.
+     * The initial value of {@code pos}
+     * is {@code 0} and the initial value
+     * of  {@code count} is the length of
+     * {@code buf}.
      *
      * @param   buf   the input buffer.
      */
@@ -107,12 +109,12 @@
     }
 
     /**
-     * Creates <code>ByteArrayInputStream</code>
-     * that uses <code>buf</code> as its
-     * buffer array. The initial value of <code>pos</code>
-     * is <code>offset</code> and the initial value
-     * of <code>count</code> is the minimum of <code>offset+length</code>
-     * and <code>buf.length</code>.
+     * Creates {@code ByteArrayInputStream}
+     * that uses {@code buf} as its
+     * buffer array. The initial value of {@code pos}
+     * is {@code offset} and the initial value
+     * of {@code count} is the minimum of {@code offset+length}
+     * and {@code buf.length}.
      * The buffer array is not copied. The buffer's mark is
      * set to the specified offset.
      *
@@ -129,15 +131,15 @@
 
     /**
      * Reads the next byte of data from this input stream. The value
-     * byte is returned as an <code>int</code> in the range
-     * <code>0</code> to <code>255</code>. If no byte is available
+     * byte is returned as an {@code int} in the range
+     * {@code 0} to {@code 255}. If no byte is available
      * because the end of the stream has been reached, the value
-     * <code>-1</code> is returned.
+     * {@code -1} is returned.
      * <p>
-     * This <code>read</code> method
+     * This {@code read} method
      * cannot block.
      *
-     * @return  the next byte of data, or <code>-1</code> if the end of the
+     * @return  the next byte of data, or {@code -1} if the end of the
      *          stream has been reached.
      */
     public synchronized int read() {
@@ -145,40 +147,30 @@
     }
 
     /**
-     * Reads up to <code>len</code> bytes of data into an array of bytes
-     * from this input stream.
-     * If <code>pos</code> equals <code>count</code>,
-     * then <code>-1</code> is returned to indicate
-     * end of file. Otherwise, the  number <code>k</code>
-     * of bytes read is equal to the smaller of
-     * <code>len</code> and <code>count-pos</code>.
-     * If <code>k</code> is positive, then bytes
-     * <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
-     * are copied into <code>b[off]</code>  through
-     * <code>b[off+k-1]</code> in the manner performed
-     * by <code>System.arraycopy</code>. The
-     * value <code>k</code> is added into <code>pos</code>
-     * and <code>k</code> is returned.
+     * Reads up to {@code len} bytes of data into an array of bytes from this
+     * input stream.  If {@code pos} equals {@code count}, then {@code -1} is
+     * returned to indicate end of file.  Otherwise, the  number {@code k} of
+     * bytes read is equal to the smaller of {@code len} and {@code count-pos}.
+     * If {@code k} is positive, then bytes {@code buf[pos]} through
+     * {@code buf[pos+k-1]} are copied into {@code b[off]} through
+     * {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
+     * The value {@code k} is added into {@code pos} and {@code k} is returned.
      * <p>
-     * This <code>read</code> method cannot block.
+     * This {@code read} method cannot block.
      *
      * @param   b     the buffer into which the data is read.
-     * @param   off   the start offset in the destination array <code>b</code>
+     * @param   off   the start offset in the destination array {@code b}
      * @param   len   the maximum number of bytes read.
      * @return  the total number of bytes read into the buffer, or
-     *          <code>-1</code> if there is no more data because the end of
+     *          {@code -1} if there is no more data because the end of
      *          the stream has been reached.
-     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
-     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
-     * <code>len</code> is negative, or <code>len</code> is greater than
-     * <code>b.length - off</code>
+     * @throws  NullPointerException If {@code b} is {@code null}.
+     * @throws  IndexOutOfBoundsException If {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code b.length - off}
      */
     public synchronized int read(byte b[], int off, int len) {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if (off < 0 || len < 0 || len > b.length - off) {
-            throw new IndexOutOfBoundsException();
-        }
+        Objects.checkFromIndexSize(off, len, b.length);
 
         if (pos >= count) {
             return -1;
@@ -196,14 +188,32 @@
         return len;
     }
 
+    public synchronized byte[] readAllBytes() {
+        byte[] result = Arrays.copyOfRange(buf, pos, count);
+        pos = count;
+        return result;
+    }
+
+    public int readNBytes(byte[] b, int off, int len) {
+        int n = read(b, off, len);
+        return n == -1 ? 0 : n;
+    }
+
+    public synchronized long transferTo(OutputStream out) throws IOException {
+        int len = count - pos;
+        out.write(buf, pos, len);
+        pos = count;
+        return len;
+    }
+
     /**
-     * Skips <code>n</code> bytes of input from this input stream. Fewer
+     * Skips {@code n} bytes of input from this input stream. Fewer
      * bytes might be skipped if the end of the input stream is reached.
-     * The actual number <code>k</code>
+     * The actual number {@code k}
      * of bytes to be skipped is equal to the smaller
-     * of <code>n</code> and  <code>count-pos</code>.
-     * The value <code>k</code> is added into <code>pos</code>
-     * and <code>k</code> is returned.
+     * of {@code n} and  {@code count-pos}.
+     * The value {@code k} is added into {@code pos}
+     * and {@code k} is returned.
      *
      * @param   n   the number of bytes to be skipped.
      * @return  the actual number of bytes skipped.
@@ -222,7 +232,7 @@
      * Returns the number of remaining bytes that can be read (or skipped over)
      * from this input stream.
      * <p>
-     * The value returned is <code>count&nbsp;- pos</code>,
+     * The value returned is {@code count - pos},
      * which is the number of bytes remaining to be read from the input buffer.
      *
      * @return  the number of remaining bytes that can be read (or skipped
@@ -233,11 +243,11 @@
     }
 
     /**
-     * Tests if this <code>InputStream</code> supports mark/reset. The
-     * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
-     * always returns <code>true</code>.
+     * Tests if this {@code InputStream} supports mark/reset. The
+     * {@code markSupported} method of {@code ByteArrayInputStream}
+     * always returns {@code true}.
      *
-     * @since   JDK1.1
+     * @since   1.1
      */
     public boolean markSupported() {
         return true;
@@ -253,10 +263,10 @@
      * offset passed to the constructor (or 0 if the offset was not
      * supplied).
      *
-     * <p> Note: The <code>readAheadLimit</code> for this class
+     * <p> Note: The {@code readAheadLimit} for this class
      *  has no meaning.
      *
-     * @since   JDK1.1
+     * @since   1.1
      */
     public void mark(int readAheadLimit) {
         mark = pos;
@@ -272,9 +282,9 @@
     }
 
     /**
-     * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+     * Closing a {@code ByteArrayInputStream} has no effect. The methods in
      * this class can be called after the stream has been closed without
-     * generating an <tt>IOException</tt>.
+     * generating an {@code IOException}.
      */
     public void close() throws IOException {
     }
diff --git a/ojluni/src/main/java/java/io/ByteArrayOutputStream.java b/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
index f1d429b..df2fdd0 100644
--- a/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
+++ b/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,21 +25,23 @@
 
 package java.io;
 
+import java.nio.charset.Charset;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * This class implements an output stream in which the data is
  * written into a byte array. The buffer automatically grows as data
  * is written to it.
- * The data can be retrieved using <code>toByteArray()</code> and
- * <code>toString()</code>.
+ * The data can be retrieved using {@code toByteArray()} and
+ * {@code toString()}.
  * <p>
- * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * Closing a {@code ByteArrayOutputStream} has no effect. The methods in
  * this class can be called after the stream has been closed without
- * generating an <tt>IOException</tt>.
+ * generating an {@code IOException}.
  *
  * @author  Arthur van Hoff
- * @since   JDK1.0
+ * @since   1.0
  */
 
 public class ByteArrayOutputStream extends OutputStream {
@@ -55,7 +57,7 @@
     protected int count;
 
     /**
-     * Creates a new byte array output stream. The buffer capacity is
+     * Creates a new {@code ByteArrayOutputStream}. The buffer capacity is
      * initially 32 bytes, though its size increases if necessary.
      */
     public ByteArrayOutputStream() {
@@ -63,11 +65,11 @@
     }
 
     /**
-     * Creates a new byte array output stream, with a buffer capacity of
+     * Creates a new {@code ByteArrayOutputStream}, with a buffer capacity of
      * the specified size, in bytes.
      *
-     * @param   size   the initial size.
-     * @exception  IllegalArgumentException if size is negative.
+     * @param  size   the initial size.
+     * @throws IllegalArgumentException if size is negative.
      */
     public ByteArrayOutputStream(int size) {
         if (size < 0) {
@@ -82,7 +84,7 @@
      * at least the number of elements specified by the minimum
      * capacity argument.
      *
-     * @param minCapacity the desired minimum capacity
+     * @param  minCapacity the desired minimum capacity
      * @throws OutOfMemoryError if {@code minCapacity < 0}.  This is
      * interpreted as a request for the unsatisfiably large capacity
      * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
@@ -127,7 +129,7 @@
     }
 
     /**
-     * Writes the specified byte to this byte array output stream.
+     * Writes the specified byte to this {@code ByteArrayOutputStream}.
      *
      * @param   b   the byte to be written.
      */
@@ -138,38 +140,56 @@
     }
 
     /**
-     * Writes <code>len</code> bytes from the specified byte array
-     * starting at offset <code>off</code> to this byte array output stream.
+     * Writes {@code len} bytes from the specified byte array
+     * starting at offset {@code off} to this {@code ByteArrayOutputStream}.
      *
      * @param   b     the data.
      * @param   off   the start offset in the data.
      * @param   len   the number of bytes to write.
+     * @throws  NullPointerException if {@code b} is {@code null}.
+     * @throws  IndexOutOfBoundsException if {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code b.length - off}
      */
     public synchronized void write(byte b[], int off, int len) {
-        if ((off < 0) || (off > b.length) || (len < 0) ||
-            ((off + len) - b.length > 0)) {
-            throw new IndexOutOfBoundsException();
-        }
+        Objects.checkFromIndexSize(off, len, b.length);
         ensureCapacity(count + len);
         System.arraycopy(b, off, buf, count, len);
         count += len;
     }
 
     /**
-     * Writes the complete contents of this byte array output stream to
-     * the specified output stream argument, as if by calling the output
-     * stream's write method using <code>out.write(buf, 0, count)</code>.
+     * Writes the complete contents of the specified byte array
+     * to this {@code ByteArrayOutputStream}.
      *
-     * @param      out   the output stream to which to write the data.
-     * @exception  IOException  if an I/O error occurs.
+     * @apiNote
+     * This method is equivalent to {@link #write(byte[],int,int)
+     * write(b, 0, b.length)}.
+     *
+     * @param   b     the data.
+     * @throws  NullPointerException if {@code b} is {@code null}.
+     * @since   11
+     */
+    public void writeBytes(byte b[]) {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Writes the complete contents of this {@code ByteArrayOutputStream} to
+     * the specified output stream argument, as if by calling the output
+     * stream's write method using {@code out.write(buf, 0, count)}.
+     *
+     * @param   out   the output stream to which to write the data.
+     * @throws  NullPointerException if {@code out} is {@code null}.
+     * @throws  IOException if an I/O error occurs.
      */
     public synchronized void writeTo(OutputStream out) throws IOException {
         out.write(buf, 0, count);
     }
 
     /**
-     * Resets the <code>count</code> field of this byte array output
-     * stream to zero, so that all currently accumulated output in the
+     * Resets the {@code count} field of this {@code ByteArrayOutputStream}
+     * to zero, so that all currently accumulated output in the
      * output stream is discarded. The output stream can be used again,
      * reusing the already allocated buffer space.
      *
@@ -187,14 +207,14 @@
      * @return  the current contents of this output stream, as a byte array.
      * @see     java.io.ByteArrayOutputStream#size()
      */
-    public synchronized byte toByteArray()[] {
+    public synchronized byte[] toByteArray() {
         return Arrays.copyOf(buf, count);
     }
 
     /**
      * Returns the current size of the buffer.
      *
-     * @return  the value of the <code>count</code> field, which is the number
+     * @return  the value of the {@code count} field, which is the number
      *          of valid bytes in this output stream.
      * @see     java.io.ByteArrayOutputStream#count
      */
@@ -204,7 +224,7 @@
 
     /**
      * Converts the buffer's contents into a string decoding bytes using the
-     * platform's default character set. The length of the new <tt>String</tt>
+     * platform's default character set. The length of the new {@code String}
      * is a function of the character set, and hence may not be equal to the
      * size of the buffer.
      *
@@ -215,7 +235,7 @@
      * required.
      *
      * @return String decoded from the buffer's contents.
-     * @since  JDK1.1
+     * @since  1.1
      */
     public synchronized String toString() {
         return new String(buf, 0, count);
@@ -223,21 +243,34 @@
 
     /**
      * Converts the buffer's contents into a string by decoding the bytes using
-     * the named {@link java.nio.charset.Charset charset}. The length of the new
-     * <tt>String</tt> is a function of the charset, and hence may not be equal
-     * to the length of the byte array.
+     * the named {@link java.nio.charset.Charset charset}.
      *
-     * <p> This method always replaces malformed-input and unmappable-character
-     * sequences with this charset's default replacement string. The {@link
-     * java.nio.charset.CharsetDecoder} class should be used when more control
-     * over the decoding process is required.
+     * <p> This method is equivalent to {@code #toString(charset)} that takes a
+     * {@link java.nio.charset.Charset charset}.
      *
-     * @param      charsetName  the name of a supported
-     *             {@link java.nio.charset.Charset charset}
-     * @return     String decoded from the buffer's contents.
-     * @exception  UnsupportedEncodingException
-     *             If the named charset is not supported
-     * @since      JDK1.1
+     * <p> An invocation of this method of the form
+     *
+     * <pre> {@code
+     *      ByteArrayOutputStream b = ...
+     *      b.toString("UTF-8")
+     *      }
+     * </pre>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <pre> {@code
+     *      ByteArrayOutputStream b = ...
+     *      b.toString(StandardCharsets.UTF_8)
+     *      }
+     * </pre>
+     *
+     *
+     * @param  charsetName  the name of a supported
+     *         {@link java.nio.charset.Charset charset}
+     * @return String decoded from the buffer's contents.
+     * @throws UnsupportedEncodingException
+     *         If the named charset is not supported
+     * @since  1.1
      */
     public synchronized String toString(String charsetName)
         throws UnsupportedEncodingException
@@ -246,20 +279,41 @@
     }
 
     /**
+     * Converts the buffer's contents into a string by decoding the bytes using
+     * the specified {@link java.nio.charset.Charset charset}. The length of the new
+     * {@code String} is a function of the charset, and hence may not be equal
+     * to the length of the byte array.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with the charset's default replacement string. The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param      charset  the {@linkplain java.nio.charset.Charset charset}
+     *             to be used to decode the {@code bytes}
+     * @return     String decoded from the buffer's contents.
+     * @since      10
+     */
+    public synchronized String toString(Charset charset) {
+        return new String(buf, 0, count, charset);
+    }
+
+    /**
      * Creates a newly allocated string. Its size is the current size of
      * the output stream and the valid contents of the buffer have been
      * copied into it. Each character <i>c</i> in the resulting string is
      * constructed from the corresponding element <i>b</i> in the byte
      * array such that:
-     * <blockquote><pre>
-     *     c == (char)(((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
-     * </pre></blockquote>
+     * <blockquote><pre>{@code
+     *     c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))
+     * }</pre></blockquote>
      *
      * @deprecated This method does not properly convert bytes into characters.
      * As of JDK&nbsp;1.1, the preferred way to do this is via the
-     * <code>toString(String enc)</code> method, which takes an encoding-name
-     * argument, or the <code>toString()</code> method, which uses the
-     * platform's default character encoding.
+     * {@link #toString(String charsetName)} or {@link #toString(Charset charset)}
+     * method, which takes an encoding-name or charset argument,
+     * or the {@code toString()} method, which uses the platform's default
+     * character encoding.
      *
      * @param      hibyte    the high byte of each resulting Unicode character.
      * @return     the current contents of the output stream, as a string.
@@ -273,9 +327,9 @@
     }
 
     /**
-     * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+     * Closing a {@code ByteArrayOutputStream} has no effect. The methods in
      * this class can be called after the stream has been closed without
-     * generating an <tt>IOException</tt>.
+     * generating an {@code IOException}.
      */
     public void close() throws IOException {
     }
diff --git a/ojluni/src/main/java/java/io/CharArrayReader.java b/ojluni/src/main/java/java/io/CharArrayReader.java
index 4140976..08b1381 100644
--- a/ojluni/src/main/java/java/io/CharArrayReader.java
+++ b/ojluni/src/main/java/java/io/CharArrayReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
  * character-input stream.
  *
  * @author      Herb Jellinek
- * @since       JDK1.1
+ * @since       1.1
  */
 public class CharArrayReader extends Reader {
     /** The character buffer. */
@@ -62,13 +62,13 @@
      * Creates a CharArrayReader from the specified array of chars.
      *
      * <p> The resulting reader will start reading at the given
-     * <tt>offset</tt>.  The total number of <tt>char</tt> values that can be
-     * read from this reader will be either <tt>length</tt> or
-     * <tt>buf.length-offset</tt>, whichever is smaller.
+     * {@code offset}.  The total number of {@code char} values that can be
+     * read from this reader will be either {@code length} or
+     * {@code buf.length-offset}, whichever is smaller.
      *
      * @throws IllegalArgumentException
-     *         If <tt>offset</tt> is negative or greater than
-     *         <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if
+     *         If {@code offset} is negative or greater than
+     *         {@code buf.length}, or if {@code length} is negative, or if
      *         the sum of these two values is negative.
      *
      * @param buf       Input buffer (not copied)
@@ -116,6 +116,7 @@
      *          the end of the stream has been reached
      *
      * @exception   IOException  If an I/O error occurs
+     * @exception   IndexOutOfBoundsException {@inheritDoc}
      */
     public int read(char b[], int off, int len) throws IOException {
         synchronized (lock) {
@@ -130,12 +131,11 @@
             if (pos >= count) {
                 return -1;
             }
-            // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+
             int avail = count - pos;
             if (len > avail) {
                 len = avail;
             }
-            // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
             if (len <= 0) {
                 return 0;
             }
@@ -160,12 +160,11 @@
     public long skip(long n) throws IOException {
         synchronized (lock) {
             ensureOpen();
-            // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+
             long avail = count - pos;
             if (n > avail) {
                 n = avail;
             }
-            // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
             if (n < 0) {
                 return 0;
             }
@@ -230,9 +229,12 @@
      * Closes the stream and releases any system resources associated with
      * it.  Once the stream has been closed, further read(), ready(),
      * mark(), reset(), or skip() invocations will throw an IOException.
-     * Closing a previously closed stream has no effect.
+     * Closing a previously closed stream has no effect. This method will block
+     * while there is another thread blocking on the reader.
      */
     public void close() {
-        buf = null;
+        synchronized (lock) {
+            buf = null;
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/io/CharArrayWriter.java b/ojluni/src/main/java/java/io/CharArrayWriter.java
index 56a5821..e8bf2c3 100644
--- a/ojluni/src/main/java/java/io/CharArrayWriter.java
+++ b/ojluni/src/main/java/java/io/CharArrayWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
  * without generating an IOException.
  *
  * @author      Herb Jellinek
- * @since       JDK1.1
+ * @since       1.1
  */
 public
 class CharArrayWriter extends Writer {
@@ -91,6 +91,11 @@
      * @param c the data to be written
      * @param off       the start offset in the data
      * @param len       the number of chars that are written
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given array
      */
     public void write(char c[], int off, int len) {
         if ((off < 0) || (off > c.length) || (len < 0) ||
@@ -114,6 +119,11 @@
      * @param  str  String to be written from
      * @param  off  Offset from which to start reading characters
      * @param  len  Number of characters to be written
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given string
      */
     public void write(String str, int off, int len) {
         synchronized (lock) {
@@ -141,21 +151,21 @@
     /**
      * Appends the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * <p> An invocation of this method of the form {@code out.append(csq)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
      *     out.write(csq.toString()) </pre>
      *
-     * <p> Depending on the specification of <tt>toString</tt> for the
-     * character sequence <tt>csq</tt>, the entire sequence may not be
-     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * <p> Depending on the specification of {@code toString} for the
+     * character sequence {@code csq}, the entire sequence may not be
+     * appended. For instance, invoking the {@code toString} method of a
      * character buffer will return a subsequence whose content depends upon
      * the buffer's position and limit.
      *
      * @param  csq
-     *         The character sequence to append.  If <tt>csq</tt> is
-     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         The character sequence to append.  If {@code csq} is
+     *         {@code null}, then the four characters {@code "null"} are
      *         appended to this writer.
      *
      * @return  This writer
@@ -163,7 +173,7 @@
      * @since  1.5
      */
     public CharArrayWriter append(CharSequence csq) {
-        String s = (csq == null ? "null" : csq.toString());
+        String s = String.valueOf(csq);
         write(s, 0, s.length());
         return this;
     }
@@ -171,8 +181,9 @@
     /**
      * Appends a subsequence of the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq, start,
-     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * <p> An invocation of this method of the form
+     * {@code out.append(csq, start, end)} when
+     * {@code csq} is not {@code null}, behaves in
      * exactly the same way as the invocation
      *
      * <pre>
@@ -180,9 +191,9 @@
      *
      * @param  csq
      *         The character sequence from which a subsequence will be
-     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
-     *         will be appended as if <tt>csq</tt> contained the four
-     *         characters <tt>"null"</tt>.
+     *         appended.  If {@code csq} is {@code null}, then characters
+     *         will be appended as if {@code csq} contained the four
+     *         characters {@code "null"}.
      *
      * @param  start
      *         The index of the first character in the subsequence
@@ -194,22 +205,21 @@
      * @return  This writer
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
-     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
-     *          <tt>csq.length()</tt>
+     *          If {@code start} or {@code end} are negative, {@code start}
+     *          is greater than {@code end}, or {@code end} is greater than
+     *          {@code csq.length()}
      *
      * @since  1.5
      */
     public CharArrayWriter append(CharSequence csq, int start, int end) {
-        String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
-        write(s, 0, s.length());
-        return this;
+        if (csq == null) csq = "null";
+        return append(csq.subSequence(start, end));
     }
 
     /**
      * Appends the specified character to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * <p> An invocation of this method of the form {@code out.append(c)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
@@ -240,7 +250,7 @@
      *
      * @return an array of chars copied from the input data.
      */
-    public char toCharArray()[] {
+    public char[] toCharArray() {
         synchronized (lock) {
             return Arrays.copyOf(buf, count);
         }
diff --git a/ojluni/src/main/java/java/io/CharConversionException.java b/ojluni/src/main/java/java/io/CharConversionException.java
index ba79fe3..832dc49 100644
--- a/ojluni/src/main/java/java/io/CharConversionException.java
+++ b/ojluni/src/main/java/java/io/CharConversionException.java
@@ -28,7 +28,7 @@
  * Base class for character conversion exceptions.
  *
  * @author      Asmus Freytag
- * @since       JDK1.1
+ * @since       1.1
  */
 public class CharConversionException
     extends java.io.IOException
diff --git a/ojluni/src/main/java/java/io/DataInput.java b/ojluni/src/main/java/java/io/DataInput.java
index 3e0f0dd..86d8d3e 100644
--- a/ojluni/src/main/java/java/io/DataInput.java
+++ b/ojluni/src/main/java/java/io/DataInput.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,87 +48,96 @@
  * may be thrown if the input stream has been
  * closed.
  *
- * <h3><a name="modified-utf-8">Modified UTF-8</a></h3>
+ * <h3><a id="modified-utf-8">Modified UTF-8</a></h3>
  * <p>
  * Implementations of the DataInput and DataOutput interfaces represent
  * Unicode strings in a format that is a slight modification of UTF-8.
  * (For information regarding the standard UTF-8 format, see section
  * <i>3.9 Unicode Encoding Forms</i> of <i>The Unicode Standard, Version
- * 4.0</i>).
- * Note that in the following table, the most significant bit appears in the
- * far left-hand column.
+ * 4.0</i>)
  *
- * <blockquote>
- *   <table border="1" cellspacing="0" cellpadding="8"
- *          summary="Bit values and bytes">
- *     <tr>
- *       <th colspan="9"><span style="font-weight:normal">
- *         All characters in the range {@code '\u005Cu0001'} to
- *         {@code '\u005Cu007F'} are represented by a single byte:</span></th>
- *     </tr>
- *     <tr>
- *       <td></td>
- *       <th colspan="8" id="bit_a">Bit Values</th>
- *     </tr>
- *     <tr>
- *       <th id="byte1_a">Byte 1</th>
- *       <td><center>0</center>
- *       <td colspan="7"><center>bits 6-0</center>
- *     </tr>
- *     <tr>
- *       <th colspan="9"><span style="font-weight:normal">
- *         The null character {@code '\u005Cu0000'} and characters
+ * <ul>
+ * <li>Characters in the range {@code '\u005Cu0001'} to
+ *         {@code '\u005Cu007F'} are represented by a single byte.
+ * <li>The null character {@code '\u005Cu0000'} and characters
  *         in the range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are
- *         represented by a pair of bytes:</span></th>
+ *         represented by a pair of bytes.
+ * <li>Characters in the range {@code '\u005Cu0800'}
+ *         to {@code '\u005CuFFFF'} are represented by three bytes.
+ * </ul>
+ *
+ *   <table class="plain" style="margin-left:2em;">
+ *     <caption>Encoding of UTF-8 values</caption>
+ *     <thead>
+ *     <tr>
+ *       <th scope="col" rowspan="2">Value</th>
+ *       <th scope="col" rowspan="2">Byte</th>
+ *       <th scope="col" colspan="8" id="bit_a">Bit Values</th>
  *     </tr>
  *     <tr>
- *       <td></td>
- *       <th colspan="8" id="bit_b">Bit Values</th>
+ *       <!-- Value -->
+ *       <!-- Byte -->
+ *       <th scope="col" style="width:3em"> 7 </th>
+ *       <th scope="col" style="width:3em"> 6 </th>
+ *       <th scope="col" style="width:3em"> 5 </th>
+ *       <th scope="col" style="width:3em"> 4 </th>
+ *       <th scope="col" style="width:3em"> 3 </th>
+ *       <th scope="col" style="width:3em"> 2 </th>
+ *       <th scope="col" style="width:3em"> 1 </th>
+ *       <th scope="col" style="width:3em"> 0 </th>
+ *     </thead>
+ *     <tbody>
+ *     <tr>
+ *       <th scope="row" style="text-align:left; font-weight:normal">
+ *         {@code \u005Cu0001} to {@code \u005Cu007F} </th>
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 1 </th>
+ *       <td style="text-align:center">0
+ *       <td colspan="7" style="text-align:right; padding-right:6em">bits 6-0
  *     </tr>
  *     <tr>
- *       <th id="byte1_b">Byte 1</th>
- *       <td><center>1</center>
- *       <td><center>1</center>
- *       <td><center>0</center>
- *       <td colspan="5"><center>bits 10-6</center>
+ *       <th scope="row" rowspan="2" style="text-align:left; font-weight:normal">
+ *           {@code \u005Cu0000},<br>
+ *           {@code \u005Cu0080} to {@code \u005Cu07FF} </th>
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 1 </th>
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">0
+ *       <td colspan="5" style="text-align:right; padding-right:6em">bits 10-6
  *     </tr>
  *     <tr>
- *       <th id="byte2_a">Byte 2</th>
- *       <td><center>1</center>
- *       <td><center>0</center>
- *       <td colspan="6"><center>bits 5-0</center>
+ *       <!-- (value) -->
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 2 </th>
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">0
+ *       <td colspan="6" style="text-align:right; padding-right:6em">bits 5-0
  *     </tr>
  *     <tr>
- *       <th colspan="9"><span style="font-weight:normal">
- *         {@code char} values in the range {@code '\u005Cu0800'}
- *         to {@code '\u005CuFFFF'} are represented by three bytes:</span></th>
+ *       <th scope="row" rowspan="3" style="text-align:left; font-weight:normal">
+ *         {@code \u005Cu0800} to {@code \u005CuFFFF} </th>
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 1 </th>
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">0
+ *       <td colspan="4" style="text-align:right; padding-right:6em">bits 15-12
  *     </tr>
  *     <tr>
- *       <td></td>
- *       <th colspan="8"id="bit_c">Bit Values</th>
+ *       <!-- (value) -->
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 2 </th>
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">0
+ *       <td colspan="6" style="text-align:right; padding-right:6em">bits 11-6
  *     </tr>
  *     <tr>
- *       <th id="byte1_c">Byte 1</th>
- *       <td><center>1</center>
- *       <td><center>1</center>
- *       <td><center>1</center>
- *       <td><center>0</center>
- *       <td colspan="4"><center>bits 15-12</center>
+ *       <!-- (value) -->
+ *       <th scope="row" style="font-weight:normal; text-align:center"> 3 </th>
+ *       <td style="text-align:center">1
+ *       <td style="text-align:center">0
+ *       <td colspan="6" style="text-align:right; padding-right:6em">bits 5-0
  *     </tr>
- *     <tr>
- *       <th id="byte2_b">Byte 2</th>
- *       <td><center>1</center>
- *       <td><center>0</center>
- *       <td colspan="6"><center>bits 11-6</center>
- *     </tr>
- *     <tr>
- *       <th id="byte3">Byte 3</th>
- *       <td><center>1</center>
- *       <td><center>0</center>
- *       <td colspan="6"><center>bits 5-0</center>
- *     </tr>
+ *     </tbody>
  *   </table>
- * </blockquote>
+ *
  * <p>
  * The differences between this format and the
  * standard UTF-8 format are the following:
@@ -143,7 +152,7 @@
  * @author  Frank Yellin
  * @see     java.io.DataInputStream
  * @see     java.io.DataOutput
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 interface DataInput {
@@ -182,10 +191,11 @@
      * not all bytes of {@code b} have been
      * updated with data from the input stream.
      *
-     * @param     b   the buffer into which the data is read.
-     * @exception  EOFException  if this stream reaches the end before reading
-     *               all the bytes.
-     * @exception  IOException   if an I/O error occurs.
+     * @param   b   the buffer into which the data is read.
+     * @throws  NullPointerException if {@code b} is {@code null}.
+     * @throws  EOFException  if this stream reaches the end before reading
+     *          all the bytes.
+     * @throws  IOException   if an I/O error occurs.
      */
     void readFully(byte b[]) throws IOException;
 
@@ -226,12 +236,16 @@
      * and so on. The number of bytes read is,
      * at most, equal to {@code len}.
      *
-     * @param     b   the buffer into which the data is read.
-     * @param off  an int specifying the offset into the data.
-     * @param len  an int specifying the number of bytes to read.
-     * @exception  EOFException  if this stream reaches the end before reading
-     *               all the bytes.
-     * @exception  IOException   if an I/O error occurs.
+     * @param   b    the buffer into which the data is read.
+     * @param   off  an int specifying the offset in the data array {@code b}.
+     * @param   len  an int specifying the number of bytes to read.
+     * @throws  NullPointerException if {@code b} is {@code null}.
+     * @throws  IndexOutOfBoundsException if {@code off} is negative,
+     *          {@code len} is negative, or {@code len} is greater than
+     *          {@code b.length - off}.
+     * @throws  EOFException  if this stream reaches the end before reading
+     *          all the bytes.
+     * @throws  IOException   if an I/O error occurs.
      */
     void readFully(byte b[], int off, int len) throws IOException;
 
diff --git a/ojluni/src/main/java/java/io/DataInputStream.java b/ojluni/src/main/java/java/io/DataInputStream.java
index 19d4067..2098344 100644
--- a/ojluni/src/main/java/java/io/DataInputStream.java
+++ b/ojluni/src/main/java/java/io/DataInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
  *
  * @author  Arthur van Hoff
  * @see     java.io.DataOutputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class DataInputStream extends FilterInputStream implements DataInput {
@@ -153,38 +153,43 @@
     }
 
     /**
-     * See the general contract of the <code>readFully</code>
-     * method of <code>DataInput</code>.
+     * See the general contract of the {@code readFully}
+     * method of {@code DataInput}.
      * <p>
      * Bytes
      * for this operation are read from the contained
      * input stream.
      *
-     * @param      b   the buffer into which the data is read.
-     * @exception  EOFException  if this input stream reaches the end before
-     *             reading all the bytes.
-     * @exception  IOException   the stream has been closed and the contained
-     *             input stream does not support reading after close, or
-     *             another I/O error occurs.
-     * @see        java.io.FilterInputStream#in
+     * @param   b   the buffer into which the data is read.
+     * @throws  NullPointerException if {@code b} is {@code null}.
+     * @throws  EOFException  if this input stream reaches the end before
+     *          reading all the bytes.
+     * @throws  IOException   the stream has been closed and the contained
+     *          input stream does not support reading after close, or
+     *          another I/O error occurs.
+     * @see     java.io.FilterInputStream#in
      */
     public final void readFully(byte b[]) throws IOException {
         readFully(b, 0, b.length);
     }
 
     /**
-     * See the general contract of the <code>readFully</code>
-     * method of <code>DataInput</code>.
+     * See the general contract of the {@code readFully}
+     * method of {@code DataInput}.
      * <p>
      * Bytes
      * for this operation are read from the contained
      * input stream.
      *
      * @param      b     the buffer into which the data is read.
-     * @param      off   the start offset of the data.
+     * @param      off   the start offset in the data array {@code b}.
      * @param      len   the number of bytes to read.
+     * @exception  NullPointerException if {@code b} is {@code null}.
+     * @exception  IndexOutOfBoundsException if {@code off} is negative,
+     *             {@code len} is negative, or {@code len} is greater than
+     *             {@code b.length - off}.
      * @exception  EOFException  if this input stream reaches the end before
-     *               reading all the bytes.
+     *             reading all the bytes.
      * @exception  IOException   the stream has been closed and the contained
      *             input stream does not support reading after close, or
      *             another I/O error occurs.
@@ -582,7 +587,7 @@
      *               valid modified UTF-8 encoding of a Unicode string.
      * @see        java.io.DataInputStream#readUnsignedShort()
      */
-    public final static String readUTF(DataInput in) throws IOException {
+    public static final String readUTF(DataInput in) throws IOException {
         int utflen = in.readUnsignedShort();
         byte[] bytearr = null;
         char[] chararr = null;
diff --git a/ojluni/src/main/java/java/io/DataOutput.java b/ojluni/src/main/java/java/io/DataOutput.java
index c6692a6..50de041 100644
--- a/ojluni/src/main/java/java/io/DataOutput.java
+++ b/ojluni/src/main/java/java/io/DataOutput.java
@@ -44,7 +44,7 @@
  * @author  Frank Yellin
  * @see     java.io.DataInput
  * @see     java.io.DataOutputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 interface DataOutput {
diff --git a/ojluni/src/main/java/java/io/DataOutputStream.java b/ojluni/src/main/java/java/io/DataOutputStream.java
index 99fafed..392abba 100644
--- a/ojluni/src/main/java/java/io/DataOutputStream.java
+++ b/ojluni/src/main/java/java/io/DataOutputStream.java
@@ -32,7 +32,7 @@
  *
  * @author  unascribed
  * @see     java.io.DataInputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class DataOutputStream extends FilterOutputStream implements DataOutput {
diff --git a/ojluni/src/main/java/java/io/EOFException.java b/ojluni/src/main/java/java/io/EOFException.java
index 536669f..446373e 100644
--- a/ojluni/src/main/java/java/io/EOFException.java
+++ b/ojluni/src/main/java/java/io/EOFException.java
@@ -36,7 +36,7 @@
  * @author  Frank Yellin
  * @see     java.io.DataInputStream
  * @see     java.io.IOException
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class EOFException extends IOException {
diff --git a/ojluni/src/main/java/java/io/Externalizable.java b/ojluni/src/main/java/java/io/Externalizable.java
index f9e88fe..f5f3f9a 100644
--- a/ojluni/src/main/java/java/io/Externalizable.java
+++ b/ojluni/src/main/java/java/io/Externalizable.java
@@ -61,7 +61,7 @@
  * @see java.io.ObjectOutput
  * @see java.io.ObjectInput
  * @see java.io.Serializable
- * @since   JDK1.1
+ * @since   1.1
  */
 public interface Externalizable extends java.io.Serializable {
     /**
diff --git a/ojluni/src/main/java/java/io/FileNotFoundException.java b/ojluni/src/main/java/java/io/FileNotFoundException.java
index 278fa1d..898a9b79 100644
--- a/ojluni/src/main/java/java/io/FileNotFoundException.java
+++ b/ojluni/src/main/java/java/io/FileNotFoundException.java
@@ -37,7 +37,7 @@
  * example when an attempt is made to open a read-only file for writing.
  *
  * @author  unascribed
- * @since   JDK1.0
+ * @since   1.0
  */
 
 public class FileNotFoundException extends IOException {
diff --git a/ojluni/src/main/java/java/io/FilenameFilter.java b/ojluni/src/main/java/java/io/FilenameFilter.java
index 25d866b..2af02e8 100644
--- a/ojluni/src/main/java/java/io/FilenameFilter.java
+++ b/ojluni/src/main/java/java/io/FilenameFilter.java
@@ -38,7 +38,7 @@
  * @author  Jonathan Payne
  * @see     java.io.File
  * @see     java.io.File#list(java.io.FilenameFilter)
- * @since   JDK1.0
+ * @since   1.0
  */
 @FunctionalInterface
 public interface FilenameFilter {
diff --git a/ojluni/src/main/java/java/io/FilterInputStream.java b/ojluni/src/main/java/java/io/FilterInputStream.java
index 10beaea..05ab5fa 100644
--- a/ojluni/src/main/java/java/io/FilterInputStream.java
+++ b/ojluni/src/main/java/java/io/FilterInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
  * and fields.
  *
  * @author  Jonathan Payne
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class FilterInputStream extends InputStream {
@@ -84,7 +84,7 @@
     }
 
     /**
-     * Reads up to <code>byte.length</code> bytes of data from this
+     * Reads up to <code>b.length</code> bytes of data from this
      * input stream into an array of bytes. This method blocks until some
      * input is available.
      * <p>
@@ -144,8 +144,7 @@
      *
      * @param      n   the number of bytes to be skipped.
      * @return     the actual number of bytes skipped.
-     * @exception  IOException  if the stream does not support seek,
-     *                          or if some other I/O error occurs.
+     * @throws     IOException  if {@code in.skip(n)} throws an IOException.
      */
     public long skip(long n) throws IOException {
         return in.skip(n);
diff --git a/ojluni/src/main/java/java/io/FilterOutputStream.java b/ojluni/src/main/java/java/io/FilterOutputStream.java
index 89f5ef5..55abe73 100644
--- a/ojluni/src/main/java/java/io/FilterOutputStream.java
+++ b/ojluni/src/main/java/java/io/FilterOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,27 +39,30 @@
  * methods as well as provide additional methods and fields.
  *
  * @author  Jonathan Payne
- * @since   JDK1.0
+ * @since   1.0
  */
-public
-class FilterOutputStream extends OutputStream {
+public class FilterOutputStream extends OutputStream {
     /**
      * The underlying output stream to be filtered.
      */
     protected OutputStream out;
 
-    // Android-added: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
     /**
      * Whether the stream is closed; implicitly initialized to false.
      */
-    private boolean closed;
+    private volatile boolean closed;
+
+    /**
+     * Object used to prevent a race on the 'closed' instance variable.
+     */
+    private final Object closeLock = new Object();
 
     /**
      * Creates an output stream filter built on top of the specified
      * underlying output stream.
      *
      * @param   out   the underlying output stream to be assigned to
-     *                the field <tt>this.out</tt> for later use, or
+     *                the field {@code this.out} for later use, or
      *                <code>null</code> if this instance is to be
      *                created without an underlying stream.
      */
@@ -72,13 +75,14 @@
      * <p>
      * The <code>write</code> method of <code>FilterOutputStream</code>
      * calls the <code>write</code> method of its underlying output stream,
-     * that is, it performs <tt>out.write(b)</tt>.
+     * that is, it performs {@code out.write(b)}.
      * <p>
-     * Implements the abstract <tt>write</tt> method of <tt>OutputStream</tt>.
+     * Implements the abstract {@code write} method of {@code OutputStream}.
      *
      * @param      b   the <code>byte</code>.
      * @exception  IOException  if an I/O error occurs.
      */
+    @Override
     public void write(int b) throws IOException {
         out.write(b);
     }
@@ -92,13 +96,14 @@
      * <code>b.length</code>.
      * <p>
      * Note that this method does not call the one-argument
-     * <code>write</code> method of its underlying stream with the single
-     * argument <code>b</code>.
+     * <code>write</code> method of its underlying output stream with
+     * the single argument <code>b</code>.
      *
      * @param      b   the data to be written.
      * @exception  IOException  if an I/O error occurs.
      * @see        java.io.FilterOutputStream#write(byte[], int, int)
      */
+    @Override
     public void write(byte b[]) throws IOException {
         write(b, 0, b.length);
     }
@@ -113,7 +118,7 @@
      * <code>byte</code> to output.
      * <p>
      * Note that this method does not call the <code>write</code> method
-     * of its underlying input stream with the same arguments. Subclasses
+     * of its underlying output stream with the same arguments. Subclasses
      * of <code>FilterOutputStream</code> should provide a more efficient
      * implementation of this method.
      *
@@ -123,6 +128,7 @@
      * @exception  IOException  if an I/O error occurs.
      * @see        java.io.FilterOutputStream#write(int)
      */
+    @Override
     public void write(byte b[], int off, int len) throws IOException {
         if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
             throw new IndexOutOfBoundsException();
@@ -142,6 +148,7 @@
      * @exception  IOException  if an I/O error occurs.
      * @see        java.io.FilterOutputStream#out
      */
+    @Override
     public void flush() throws IOException {
         out.flush();
     }
@@ -158,21 +165,17 @@
      * @see        java.io.FilterOutputStream#flush()
      * @see        java.io.FilterOutputStream#out
      */
-    // BEGIN Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
-    /*
-    @SuppressWarnings("try")
-    public void close() throws IOException {
-        try (OutputStream ostream = out) {
-            flush();
-        }
-    }
-    */
     @Override
     public void close() throws IOException {
         if (closed) {
             return;
         }
-        closed = true;
+        synchronized (closeLock) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
 
         Throwable flushException = null;
         try {
@@ -203,5 +206,4 @@
             }
         }
     }
-    // END Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
 }
diff --git a/ojluni/src/main/java/java/io/FilterReader.java b/ojluni/src/main/java/java/io/FilterReader.java
index 0826230..60f748f 100644
--- a/ojluni/src/main/java/java/io/FilterReader.java
+++ b/ojluni/src/main/java/java/io/FilterReader.java
@@ -35,7 +35,7 @@
  * additional methods and fields.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public abstract class FilterReader extends Reader {
@@ -69,6 +69,7 @@
      * Reads characters into a portion of an array.
      *
      * @exception  IOException  If an I/O error occurs
+     * @exception  IndexOutOfBoundsException {@inheritDoc}
      */
     public int read(char cbuf[], int off, int len) throws IOException {
         return in.read(cbuf, off, len);
diff --git a/ojluni/src/main/java/java/io/FilterWriter.java b/ojluni/src/main/java/java/io/FilterWriter.java
index fb307d5..8272b3c 100644
--- a/ojluni/src/main/java/java/io/FilterWriter.java
+++ b/ojluni/src/main/java/java/io/FilterWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
  * provide additional methods and fields.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public abstract class FilterWriter extends Writer {
@@ -72,7 +72,12 @@
      * @param  off   Offset from which to start reading characters
      * @param  len   Number of characters to be written
      *
-     * @exception  IOException  If an I/O error occurs
+     * @throws  IndexOutOfBoundsException
+     *          If the values of the {@code off} and {@code len} parameters
+     *          cause the corresponding method of the underlying {@code Writer}
+     *          to throw an {@code IndexOutOfBoundsException}
+     *
+     * @throws  IOException  If an I/O error occurs
      */
     public void write(char cbuf[], int off, int len) throws IOException {
         out.write(cbuf, off, len);
@@ -85,7 +90,12 @@
      * @param  off  Offset from which to start reading characters
      * @param  len  Number of characters to be written
      *
-     * @exception  IOException  If an I/O error occurs
+     * @throws  IndexOutOfBoundsException
+     *          If the values of the {@code off} and {@code len} parameters
+     *          cause the corresponding method of the underlying {@code Writer}
+     *          to throw an {@code IndexOutOfBoundsException}
+     *
+     * @throws  IOException  If an I/O error occurs
      */
     public void write(String str, int off, int len) throws IOException {
         out.write(str, off, len);
diff --git a/ojluni/src/main/java/java/io/Flushable.java b/ojluni/src/main/java/java/io/Flushable.java
index fe90fbd..9bdc56e 100644
--- a/ojluni/src/main/java/java/io/Flushable.java
+++ b/ojluni/src/main/java/java/io/Flushable.java
@@ -28,7 +28,7 @@
 import java.io.IOException;
 
 /**
- * A <tt>Flushable</tt> is a destination of data that can be flushed.  The
+ * A {@code Flushable} is a destination of data that can be flushed.  The
  * flush method is invoked to write any buffered output to the underlying
  * stream.
  *
diff --git a/ojluni/src/main/java/java/io/IOError.java b/ojluni/src/main/java/java/io/IOError.java
index f9626cd..ea9ec0f 100644
--- a/ojluni/src/main/java/java/io/IOError.java
+++ b/ojluni/src/main/java/java/io/IOError.java
@@ -35,11 +35,11 @@
     /**
      * Constructs a new instance of IOError with the specified cause. The
      * IOError is created with the detail message of
-     * <tt>(cause==null ? null : cause.toString())</tt> (which typically
+     * {@code (cause==null ? null : cause.toString())} (which typically
      * contains the class and detail message of cause).
      *
      * @param  cause
-     *         The cause of this error, or <tt>null</tt> if the cause
+     *         The cause of this error, or {@code null} if the cause
      *         is not known
      */
     public IOError(Throwable cause) {
diff --git a/ojluni/src/main/java/java/io/IOException.java b/ojluni/src/main/java/java/io/IOException.java
index 745b579..c0d6ea5 100644
--- a/ojluni/src/main/java/java/io/IOException.java
+++ b/ojluni/src/main/java/java/io/IOException.java
@@ -33,7 +33,7 @@
  * @author  unascribed
  * @see     java.io.InputStream
  * @see     java.io.OutputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class IOException extends Exception {
diff --git a/ojluni/src/main/java/java/io/InputStream.java b/ojluni/src/main/java/java/io/InputStream.java
index 6c46a40..7bccfaf 100644
--- a/ojluni/src/main/java/java/io/InputStream.java
+++ b/ojluni/src/main/java/java/io/InputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,11 @@
 
 package java.io;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
 /**
  * This abstract class is the superclass of all classes representing
  * an input stream of bytes.
@@ -40,7 +45,7 @@
  * @see     java.io.InputStream#read()
  * @see     java.io.OutputStream
  * @see     java.io.PushbackInputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public abstract class InputStream implements Closeable {
 
@@ -48,6 +53,105 @@
     // use when skipping.
     private static final int MAX_SKIP_BUFFER_SIZE = 2048;
 
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    /**
+     * Returns a new {@code InputStream} that reads no bytes. The returned
+     * stream is initially open.  The stream is closed by calling the
+     * {@code close()} method.  Subsequent calls to {@code close()} have no
+     * effect.
+     *
+     * <p> While the stream is open, the {@code available()}, {@code read()},
+     * {@code read(byte[])}, {@code read(byte[], int, int)},
+     * {@code readAllBytes()}, {@code readNBytes(byte[], int, int)},
+     * {@code readNBytes(int)}, {@code skip(long)}, and
+     * {@code transferTo()} methods all behave as if end of stream has been
+     * reached.  After the stream has been closed, these methods all throw
+     * {@code IOException}.
+     *
+     * <p> The {@code markSupported()} method returns {@code false}.  The
+     * {@code mark()} method does nothing, and the {@code reset()} method
+     * throws {@code IOException}.
+     *
+     * @return an {@code InputStream} which contains no bytes
+     *
+     * @since 11
+     */
+    public static InputStream nullInputStream() {
+        return new InputStream() {
+            private volatile boolean closed;
+
+            private void ensureOpen() throws IOException {
+                if (closed) {
+                    throw new IOException("Stream closed");
+                }
+            }
+
+            @Override
+            public int available () throws IOException {
+                ensureOpen();
+                return 0;
+            }
+
+            @Override
+            public int read() throws IOException {
+                ensureOpen();
+                return -1;
+            }
+
+            @Override
+            public int read(byte[] b, int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, b.length);
+                if (len == 0) {
+                    return 0;
+                }
+                ensureOpen();
+                return -1;
+            }
+
+            @Override
+            public byte[] readAllBytes() throws IOException {
+                ensureOpen();
+                return new byte[0];
+            }
+
+            @Override
+            public int readNBytes(byte[] b, int off, int len)
+                throws IOException {
+                Objects.checkFromIndexSize(off, len, b.length);
+                ensureOpen();
+                return 0;
+            }
+
+            @Override
+            public byte[] readNBytes(int len) throws IOException {
+                if (len < 0) {
+                    throw new IllegalArgumentException("len < 0");
+                }
+                ensureOpen();
+                return new byte[0];
+            }
+
+            @Override
+            public long skip(long n) throws IOException {
+                ensureOpen();
+                return 0L;
+            }
+
+            @Override
+            public long transferTo(OutputStream out) throws IOException {
+                Objects.requireNonNull(out);
+                ensureOpen();
+                return 0L;
+            }
+
+            @Override
+            public void close() throws IOException {
+                closed = true;
+            }
+        };
+    }
+
     /**
      * Reads the next byte of data from the input stream. The value byte is
      * returned as an <code>int</code> in the range <code>0</code> to
@@ -139,8 +243,8 @@
      * <code>b</code> and the number of bytes read before the exception
      * occurred is returned. The default implementation of this method blocks
      * until the requested amount of input data <code>len</code> has been read,
-     * end of file is detected, or an exception is thrown. Subclasses are encouraged
-     * to provide a more efficient implementation of this method.
+     * end of file is detected, or an exception is thrown. Subclasses are
+     * encouraged to provide a more efficient implementation of this method.
      *
      * @param      b     the buffer into which the data is read.
      * @param      off   the start offset in array <code>b</code>
@@ -159,11 +263,8 @@
      * @see        java.io.InputStream#read()
      */
     public int read(byte b[], int off, int len) throws IOException {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if (off < 0 || len < 0 || len > b.length - off) {
-            throw new IndexOutOfBoundsException();
-        } else if (len == 0) {
+        Objects.checkFromIndexSize(off, len, b.length);
+        if (len == 0) {
             return 0;
         }
 
@@ -188,6 +289,213 @@
     }
 
     /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Reads all remaining bytes from the input stream. This method blocks until
+     * all remaining bytes have been read and end of stream is detected, or an
+     * exception is thrown. This method does not close the input stream.
+     *
+     * <p> When this stream reaches end of stream, further invocations of this
+     * method will return an empty byte array.
+     *
+     * <p> Note that this method is intended for simple cases where it is
+     * convenient to read all bytes into a byte array. It is not intended for
+     * reading input streams with large amounts of data.
+     *
+     * <p> The behavior for the case where the input stream is <i>asynchronously
+     * closed</i>, or the thread interrupted during the read, is highly input
+     * stream specific, and therefore not specified.
+     *
+     * <p> If an I/O error occurs reading from the input stream, then it may do
+     * so after some, but not all, bytes have been read. Consequently the input
+     * stream may not be at end of stream and may be in an inconsistent state.
+     * It is strongly recommended that the stream be promptly closed if an I/O
+     * error occurs.
+     *
+     * @implSpec
+     * This method invokes {@link #readNBytes(int)} with a length of
+     * {@link Integer#MAX_VALUE}.
+     *
+     * @return a byte array containing the bytes read from this input stream
+     * @throws IOException if an I/O error occurs
+     * @throws OutOfMemoryError if an array of the required size cannot be
+     *         allocated.
+     *
+     * @since 9
+     */
+    public byte[] readAllBytes() throws IOException {
+        return readNBytes(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Reads up to a specified number of bytes from the input stream. This
+     * method blocks until the requested number of bytes have been read, end
+     * of stream is detected, or an exception is thrown. This method does not
+     * close the input stream.
+     *
+     * <p> The length of the returned array equals the number of bytes read
+     * from the stream. If {@code len} is zero, then no bytes are read and
+     * an empty byte array is returned. Otherwise, up to {@code len} bytes
+     * are read from the stream. Fewer than {@code len} bytes may be read if
+     * end of stream is encountered.
+     *
+     * <p> When this stream reaches end of stream, further invocations of this
+     * method will return an empty byte array.
+     *
+     * <p> Note that this method is intended for simple cases where it is
+     * convenient to read the specified number of bytes into a byte array. The
+     * total amount of memory allocated by this method is proportional to the
+     * number of bytes read from the stream which is bounded by {@code len}.
+     * Therefore, the method may be safely called with very large values of
+     * {@code len} provided sufficient memory is available.
+     *
+     * <p> The behavior for the case where the input stream is <i>asynchronously
+     * closed</i>, or the thread interrupted during the read, is highly input
+     * stream specific, and therefore not specified.
+     *
+     * <p> If an I/O error occurs reading from the input stream, then it may do
+     * so after some, but not all, bytes have been read. Consequently the input
+     * stream may not be at end of stream and may be in an inconsistent state.
+     * It is strongly recommended that the stream be promptly closed if an I/O
+     * error occurs.
+     *
+     * @implNote
+     * The number of bytes allocated to read data from this stream and return
+     * the result is bounded by {@code 2*(long)len}, inclusive.
+     *
+     * @param len the maximum number of bytes to read
+     * @return a byte array containing the bytes read from this input stream
+     * @throws IllegalArgumentException if {@code length} is negative
+     * @throws IOException if an I/O error occurs
+     * @throws OutOfMemoryError if an array of the required size cannot be
+     *         allocated.
+     *
+     * @since 11
+     */
+    public byte[] readNBytes(int len) throws IOException {
+        if (len < 0) {
+            throw new IllegalArgumentException("len < 0");
+        }
+
+        List<byte[]> bufs = null;
+        byte[] result = null;
+        int total = 0;
+        int remaining = len;
+        int n;
+        do {
+            byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)];
+            int nread = 0;
+
+            // read to EOF which may read more or less than buffer size
+            while ((n = read(buf, nread,
+                    Math.min(buf.length - nread, remaining))) > 0) {
+                nread += n;
+                remaining -= n;
+            }
+
+            if (nread > 0) {
+                if (MAX_BUFFER_SIZE - total < nread) {
+                    throw new OutOfMemoryError("Required array size too large");
+                }
+                total += nread;
+                if (result == null) {
+                    result = buf;
+                } else {
+                    if (bufs == null) {
+                        bufs = new ArrayList<>();
+                        bufs.add(result);
+                    }
+                    bufs.add(buf);
+                }
+            }
+            // if the last call to read returned -1 or the number of bytes
+            // requested have been read then break
+        } while (n >= 0 && remaining > 0);
+
+        if (bufs == null) {
+            if (result == null) {
+                return new byte[0];
+            }
+            return result.length == total ?
+                result : Arrays.copyOf(result, total);
+        }
+
+        result = new byte[total];
+        int offset = 0;
+        remaining = total;
+        for (byte[] b : bufs) {
+            int count = Math.min(b.length, remaining);
+            System.arraycopy(b, 0, result, offset, count);
+            offset += count;
+            remaining -= count;
+        }
+
+        return result;
+    }
+
+    /**
+     * Reads the requested number of bytes from the input stream into the given
+     * byte array. This method blocks until {@code len} bytes of input data have
+     * been read, end of stream is detected, or an exception is thrown. The
+     * number of bytes actually read, possibly zero, is returned. This method
+     * does not close the input stream.
+     *
+     * <p> In the case where end of stream is reached before {@code len} bytes
+     * have been read, then the actual number of bytes read will be returned.
+     * When this stream reaches end of stream, further invocations of this
+     * method will return zero.
+     *
+     * <p> If {@code len} is zero, then no bytes are read and {@code 0} is
+     * returned; otherwise, there is an attempt to read up to {@code len} bytes.
+     *
+     * <p> The first byte read is stored into element {@code b[off]}, the next
+     * one in to {@code b[off+1]}, and so on. The number of bytes read is, at
+     * most, equal to {@code len}. Let <i>k</i> be the number of bytes actually
+     * read; these bytes will be stored in elements {@code b[off]} through
+     * {@code b[off+}<i>k</i>{@code -1]}, leaving elements {@code b[off+}<i>k</i>
+     * {@code ]} through {@code b[off+len-1]} unaffected.
+     *
+     * <p> The behavior for the case where the input stream is <i>asynchronously
+     * closed</i>, or the thread interrupted during the read, is highly input
+     * stream specific, and therefore not specified.
+     *
+     * <p> If an I/O error occurs reading from the input stream, then it may do
+     * so after some, but not all, bytes of {@code b} have been updated with
+     * data from the input stream. Consequently the input stream and {@code b}
+     * may be in an inconsistent state. It is strongly recommended that the
+     * stream be promptly closed if an I/O error occurs.
+     *
+     * @param  b the byte array into which the data is read
+     * @param  off the start offset in {@code b} at which the data is written
+     * @param  len the maximum number of bytes to read
+     * @return the actual number of bytes read into the buffer
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code b} is {@code null}
+     * @throws IndexOutOfBoundsException If {@code off} is negative, {@code len}
+     *         is negative, or {@code len} is greater than {@code b.length - off}
+     *
+     * @since 9
+     */
+    public int readNBytes(byte[] b, int off, int len) throws IOException {
+        Objects.checkFromIndexSize(off, len, b.length);
+
+        int n = 0;
+        while (n < len) {
+            int count = read(b, off + n, len - n);
+            if (count < 0)
+                break;
+            n += count;
+        }
+        return n;
+    }
+
+    /**
      * Skips over and discards <code>n</code> bytes of data from this input
      * stream. The <code>skip</code> method may, for a variety of reasons, end
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
@@ -198,7 +506,7 @@
      * returns 0, and no bytes are skipped. Subclasses may handle the negative
      * value differently.
      *
-     * <p> The <code>skip</code> method of this class creates a
+     * <p> The <code>skip</code> method implementation of this class creates a
      * byte array and then repeatedly reads into it until <code>n</code> bytes
      * have been read or the end of the stream has been reached. Subclasses are
      * encouraged to provide a more efficient implementation of this method.
@@ -206,8 +514,7 @@
      *
      * @param      n   the number of bytes to be skipped.
      * @return     the actual number of bytes skipped.
-     * @exception  IOException  if the stream does not support seek,
-     *                          or if some other I/O error occurs.
+     * @throws     IOException  if an I/O error occurs.
      */
     public long skip(long n) throws IOException {
 
@@ -232,29 +539,29 @@
     }
 
     /**
-     * Returns an estimate of the number of bytes that can be read (or
-     * skipped over) from this input stream without blocking by the next
-     * invocation of a method for this input stream. The next invocation
-     * might be the same thread or another thread.  A single read or skip of this
-     * many bytes will not block, but may read or skip fewer bytes.
+     * Returns an estimate of the number of bytes that can be read (or skipped
+     * over) from this input stream without blocking, which may be 0, or 0 when
+     * end of stream is detected.  The read might be on the same thread or
+     * another thread.  A single read or skip of this many bytes will not block,
+     * but may read or skip fewer bytes.
      *
-     * <p> Note that while some implementations of {@code InputStream} will return
-     * the total number of bytes in the stream, many will not.  It is
+     * <p> Note that while some implementations of {@code InputStream} will
+     * return the total number of bytes in the stream, many will not.  It is
      * never correct to use the return value of this method to allocate
      * a buffer intended to hold all data in this stream.
      *
-     * <p> A subclass' implementation of this method may choose to throw an
-     * {@link IOException} if this input stream has been closed by
-     * invoking the {@link #close()} method.
+     * <p> A subclass's implementation of this method may choose to throw an
+     * {@link IOException} if this input stream has been closed by invoking the
+     * {@link #close()} method.
      *
-     * <p> The {@code available} method for class {@code InputStream} always
-     * returns {@code 0}.
+     * <p> The {@code available} method of {@code InputStream} always returns
+     * {@code 0}.
      *
      * <p> This method should be overridden by subclasses.
      *
-     * @return     an estimate of the number of bytes that can be read (or skipped
-     *             over) from this input stream without blocking or {@code 0} when
-     *             it reaches the end of the input stream.
+     * @return     an estimate of the number of bytes that can be read (or
+     *             skipped over) from this input stream without blocking or
+     *             {@code 0} when it reaches the end of the input stream.
      * @exception  IOException if an I/O error occurs.
      */
     public int available() throws IOException {
@@ -364,4 +671,40 @@
         return false;
     }
 
+    /**
+     * Reads all bytes from this input stream and writes the bytes to the
+     * given output stream in the order that they are read. On return, this
+     * input stream will be at end of stream. This method does not close either
+     * stream.
+     * <p>
+     * This method may block indefinitely reading from the input stream, or
+     * writing to the output stream. The behavior for the case where the input
+     * and/or output stream is <i>asynchronously closed</i>, or the thread
+     * interrupted during the transfer, is highly input and output stream
+     * specific, and therefore not specified.
+     * <p>
+     * If an I/O error occurs reading from the input stream or writing to the
+     * output stream, then it may do so after some bytes have been read or
+     * written. Consequently the input stream may not be at end of stream and
+     * one, or both, streams may be in an inconsistent state. It is strongly
+     * recommended that both streams be promptly closed if an I/O error occurs.
+     *
+     * @param  out the output stream, non-null
+     * @return the number of bytes transferred
+     * @throws IOException if an I/O error occurs when reading or writing
+     * @throws NullPointerException if {@code out} is {@code null}
+     *
+     * @since 9
+     */
+    public long transferTo(OutputStream out) throws IOException {
+        Objects.requireNonNull(out, "out");
+        long transferred = 0;
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+        int read;
+        while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
+            out.write(buffer, 0, read);
+            transferred += read;
+        }
+        return transferred;
+    }
 }
diff --git a/ojluni/src/main/java/java/io/InputStreamReader.java b/ojluni/src/main/java/java/io/InputStreamReader.java
index e131dca..564537e 100644
--- a/ojluni/src/main/java/java/io/InputStreamReader.java
+++ b/ojluni/src/main/java/java/io/InputStreamReader.java
@@ -56,7 +56,7 @@
  * @see java.nio.charset.Charset
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class InputStreamReader extends Reader {
diff --git a/ojluni/src/main/java/java/io/InvalidClassException.java b/ojluni/src/main/java/java/io/InvalidClassException.java
index 77f0a5a..3d78c6b 100644
--- a/ojluni/src/main/java/java/io/InvalidClassException.java
+++ b/ojluni/src/main/java/java/io/InvalidClassException.java
@@ -36,7 +36,7 @@
  * </UL>
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class InvalidClassException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/InvalidObjectException.java b/ojluni/src/main/java/java/io/InvalidObjectException.java
index fbe1108..5853911 100644
--- a/ojluni/src/main/java/java/io/InvalidObjectException.java
+++ b/ojluni/src/main/java/java/io/InvalidObjectException.java
@@ -30,10 +30,10 @@
  * tests.  The argument should provide the reason for the failure.
  *
  * @see ObjectInputValidation
- * @since JDK1.1
+ * @since 1.1
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class InvalidObjectException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/LineNumberInputStream.java b/ojluni/src/main/java/java/io/LineNumberInputStream.java
index 1f37a98..2235a2b 100644
--- a/ojluni/src/main/java/java/io/LineNumberInputStream.java
+++ b/ojluni/src/main/java/java/io/LineNumberInputStream.java
@@ -40,7 +40,7 @@
  *
  * @author     Arthur van Hoff
  * @see        java.io.LineNumberReader
- * @since      JDK1.0
+ * @since      1.0
  * @deprecated This class incorrectly assumes that bytes adequately represent
  *             characters.  As of JDK&nbsp;1.1, the preferred way to operate on
  *             character streams is via the new character-stream classes, which
diff --git a/ojluni/src/main/java/java/io/LineNumberReader.java b/ojluni/src/main/java/java/io/LineNumberReader.java
index 29884fd..c9ecbe0 100644
--- a/ojluni/src/main/java/java/io/LineNumberReader.java
+++ b/ojluni/src/main/java/java/io/LineNumberReader.java
@@ -34,17 +34,17 @@
  *
  * <p> By default, line numbering begins at 0. This number increments at every
  * <a href="#lt">line terminator</a> as the data is read, and can be changed
- * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
- * <tt>setLineNumber(int)</tt> does not actually change the current position in
+ * with a call to {@code setLineNumber(int)}.  Note however, that
+ * {@code setLineNumber(int)} does not actually change the current position in
  * the stream; it only changes the value that will be returned by
- * <tt>getLineNumber()</tt>.
+ * {@code getLineNumber()}.
  *
- * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
+ * <p> A line is considered to be <a id="lt">terminated</a> by any one of a
  * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
  * immediately by a linefeed.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class LineNumberReader extends BufferedReader {
@@ -159,6 +159,8 @@
      *
      * @throws  IOException
      *          If an I/O error occurs
+     *
+     * @throws  IndexOutOfBoundsException {@inheritDoc}
      */
     @SuppressWarnings("fallthrough")
     public int read(char cbuf[], int off, int len) throws IOException {
@@ -191,7 +193,7 @@
      *
      * @return  A String containing the contents of the line, not including
      *          any <a href="#lt">line termination characters</a>, or
-     *          <tt>null</tt> if the end of the stream has been reached
+     *          {@code null} if the end of the stream has been reached
      *
      * @throws  IOException
      *          If an I/O error occurs
@@ -224,7 +226,7 @@
      *          If an I/O error occurs
      *
      * @throws  IllegalArgumentException
-     *          If <tt>n</tt> is negative
+     *          If {@code n} is negative
      */
     public long skip(long n) throws IOException {
         if (n < 0)
diff --git a/ojluni/src/main/java/java/io/NotActiveException.java b/ojluni/src/main/java/java/io/NotActiveException.java
index 13291e6..231598c 100644
--- a/ojluni/src/main/java/java/io/NotActiveException.java
+++ b/ojluni/src/main/java/java/io/NotActiveException.java
@@ -29,7 +29,7 @@
  * Thrown when serialization or deserialization is not active.
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class NotActiveException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/NotSerializableException.java b/ojluni/src/main/java/java/io/NotSerializableException.java
index 70e4f57..43dbc1a 100644
--- a/ojluni/src/main/java/java/io/NotSerializableException.java
+++ b/ojluni/src/main/java/java/io/NotSerializableException.java
@@ -31,7 +31,7 @@
  * this exception. The argument should be the name of the class.
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class NotSerializableException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/ObjectInput.java b/ojluni/src/main/java/java/io/ObjectInput.java
index bc7c26b..92d3b70 100644
--- a/ojluni/src/main/java/java/io/ObjectInput.java
+++ b/ojluni/src/main/java/java/io/ObjectInput.java
@@ -34,7 +34,7 @@
  * @see java.io.InputStream
  * @see java.io.ObjectOutputStream
  * @see java.io.ObjectInputStream
- * @since   JDK1.1
+ * @since   1.1
  */
 public interface ObjectInput extends DataInput, AutoCloseable {
     /**
diff --git a/ojluni/src/main/java/java/io/ObjectInputValidation.java b/ojluni/src/main/java/java/io/ObjectInputValidation.java
index dc6f842..09ee8a6 100644
--- a/ojluni/src/main/java/java/io/ObjectInputValidation.java
+++ b/ojluni/src/main/java/java/io/ObjectInputValidation.java
@@ -33,7 +33,7 @@
  * @author  unascribed
  * @see     ObjectInputStream
  * @see     ObjectInputStream#registerValidation(java.io.ObjectInputValidation, int)
- * @since   JDK1.1
+ * @since   1.1
  */
 public interface ObjectInputValidation {
     /**
diff --git a/ojluni/src/main/java/java/io/ObjectOutput.java b/ojluni/src/main/java/java/io/ObjectOutput.java
index 7c2cbeb..720d198 100644
--- a/ojluni/src/main/java/java/io/ObjectOutput.java
+++ b/ojluni/src/main/java/java/io/ObjectOutput.java
@@ -34,7 +34,7 @@
  * @see java.io.InputStream
  * @see java.io.ObjectOutputStream
  * @see java.io.ObjectInputStream
- * @since   JDK1.1
+ * @since   1.1
  */
 public interface ObjectOutput extends DataOutput, AutoCloseable {
     /**
diff --git a/ojluni/src/main/java/java/io/ObjectStreamException.java b/ojluni/src/main/java/java/io/ObjectStreamException.java
index 889cad3..94fc560 100644
--- a/ojluni/src/main/java/java/io/ObjectStreamException.java
+++ b/ojluni/src/main/java/java/io/ObjectStreamException.java
@@ -29,7 +29,7 @@
  * Superclass of all exceptions specific to Object Stream classes.
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public abstract class ObjectStreamException extends IOException {
 
@@ -38,10 +38,10 @@
     /**
      * Create an ObjectStreamException with the specified argument.
      *
-     * @param classname the detailed message for the exception
+     * @param message the detailed message for the exception
      */
-    protected ObjectStreamException(String classname) {
-        super(classname);
+    protected ObjectStreamException(String message) {
+        super(message);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/io/OptionalDataException.java b/ojluni/src/main/java/java/io/OptionalDataException.java
index 91283fd..f51e0ac 100644
--- a/ojluni/src/main/java/java/io/OptionalDataException.java
+++ b/ojluni/src/main/java/java/io/OptionalDataException.java
@@ -43,7 +43,7 @@
  * </ul>
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class OptionalDataException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/OutputStream.java b/ojluni/src/main/java/java/io/OutputStream.java
index c6dd7de..556e7e0 100644
--- a/ojluni/src/main/java/java/io/OutputStream.java
+++ b/ojluni/src/main/java/java/io/OutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package java.io;
 
+import java.util.Objects;
+
 /**
  * This abstract class is the superclass of all classes representing
  * an output stream of bytes. An output stream accepts output bytes
@@ -41,10 +43,55 @@
  * @see     java.io.FilterOutputStream
  * @see     java.io.InputStream
  * @see     java.io.OutputStream#write(int)
- * @since   JDK1.0
+ * @since   1.0
  */
 public abstract class OutputStream implements Closeable, Flushable {
     /**
+     * Returns a new {@code OutputStream} which discards all bytes.  The
+     * returned stream is initially open.  The stream is closed by calling
+     * the {@code close()} method.  Subsequent calls to {@code close()} have
+     * no effect.
+     *
+     * <p> While the stream is open, the {@code write(int)}, {@code
+     * write(byte[])}, and {@code write(byte[], int, int)} methods do nothing.
+     * After the stream has been closed, these methods all throw {@code
+     * IOException}.
+     *
+     * <p> The {@code flush()} method does nothing.
+     *
+     * @return an {@code OutputStream} which discards all bytes
+     *
+     * @since 11
+     */
+    public static OutputStream nullOutputStream() {
+        return new OutputStream() {
+            private volatile boolean closed;
+
+            private void ensureOpen() throws IOException {
+                if (closed) {
+                    throw new IOException("Stream closed");
+                }
+            }
+
+            @Override
+            public void write(int b) throws IOException {
+                ensureOpen();
+            }
+
+            @Override
+            public void write(byte b[], int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, b.length);
+                ensureOpen();
+            }
+
+            @Override
+            public void close() {
+                closed = true;
+            }
+        };
+    }
+
+    /**
      * Writes the specified byte to this output stream. The general
      * contract for <code>write</code> is that one byte is written
      * to the output stream. The byte to be written is the eight
@@ -94,7 +141,7 @@
      * <p>
      * If <code>off</code> is negative, or <code>len</code> is negative, or
      * <code>off+len</code> is greater than the length of the array
-     * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
+     * {@code b}, then an {@code IndexOutOfBoundsException} is thrown.
      *
      * @param      b     the data.
      * @param      off   the start offset in the data.
@@ -104,14 +151,8 @@
      *             stream is closed.
      */
     public void write(byte b[], int off, int len) throws IOException {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if ((off < 0) || (off > b.length) || (len < 0) ||
-                   ((off + len) > b.length) || ((off + len) < 0)) {
-            throw new IndexOutOfBoundsException();
-        } else if (len == 0) {
-            return;
-        }
+        Objects.checkFromIndexSize(off, len, b.length);
+        // len == 0 condition implicitly handled by loop bounds
         for (int i = 0 ; i < len ; i++) {
             write(b[off + i]);
         }
diff --git a/ojluni/src/main/java/java/io/PipedInputStream.java b/ojluni/src/main/java/java/io/PipedInputStream.java
index b79bcbd..b1be6b4 100644
--- a/ojluni/src/main/java/java/io/PipedInputStream.java
+++ b/ojluni/src/main/java/java/io/PipedInputStream.java
@@ -42,18 +42,18 @@
  * The piped input stream contains a buffer,
  * decoupling read operations from write operations,
  * within limits.
- * A pipe is said to be <a name="BROKEN"> <i>broken</i> </a> if a
+ * A pipe is said to be <a id="BROKEN"> <i>broken</i> </a> if a
  * thread that was providing data bytes to the connected
  * piped output stream is no longer alive.
  *
  * @author  James Gosling
  * @see     java.io.PipedOutputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public class PipedInputStream extends InputStream {
-    boolean closedByWriter = false;
-    volatile boolean closedByReader = false;
-    boolean connected = false;
+    boolean closedByWriter;
+    volatile boolean closedByReader;
+    boolean connected;
 
         /* REMIND: identification of the read and write sides needs to be
            more sophisticated.  Either using thread groups (but what about
@@ -66,7 +66,7 @@
 
     /**
      * The default size of the pipe's circular input buffer.
-     * @since   JDK1.1
+     * @since   1.1
      */
     // This used to be a constant before the pipe size was allowed
     // to change. This field will continue to be maintained
@@ -75,7 +75,7 @@
 
     /**
      * The circular buffer into which incoming data is placed.
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected byte buffer[];
 
@@ -84,14 +84,14 @@
      * next byte of data will be stored when received from the connected
      * piped output stream. <code>in&lt;0</code> implies the buffer is empty,
      * <code>in==out</code> implies the buffer is full
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected int in = -1;
 
     /**
      * The index of the position in the circular buffer at which the next
      * byte of data will be read by this piped input stream.
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected int out = 0;
 
@@ -198,7 +198,7 @@
      * @exception IOException If the pipe is <a href="#BROKEN"> <code>broken</code></a>,
      *          {@link #connect(java.io.PipedOutputStream) unconnected},
      *          closed, or if an I/O error occurs.
-     * @since     JDK1.1
+     * @since     1.1
      */
     protected synchronized void receive(int b) throws IOException {
         checkStateForReceive();
@@ -428,7 +428,7 @@
      *          <a href="#BROKEN"> <code>broken</code></a>.
      *
      * @exception  IOException  if an I/O error occurs.
-     * @since   JDK1.0.2
+     * @since   1.0.2
      */
     public synchronized int available() throws IOException {
         if(in < 0)
diff --git a/ojluni/src/main/java/java/io/PipedOutputStream.java b/ojluni/src/main/java/java/io/PipedOutputStream.java
index feed73a..79ffd38 100644
--- a/ojluni/src/main/java/java/io/PipedOutputStream.java
+++ b/ojluni/src/main/java/java/io/PipedOutputStream.java
@@ -35,13 +35,13 @@
  * read from the connected <code>PipedInputStream</code> by some
  * other thread. Attempting to use both objects from a single thread
  * is not recommended as it may deadlock the thread.
- * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
+ * The pipe is said to be <a id=BROKEN> <i>broken</i> </a> if a
  * thread that was reading data bytes from the connected piped input
  * stream is no longer alive.
  *
  * @author  James Gosling
  * @see     java.io.PipedInputStream
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class PipedOutputStream extends OutputStream {
diff --git a/ojluni/src/main/java/java/io/PipedReader.java b/ojluni/src/main/java/java/io/PipedReader.java
index d72e1e5..fe6b0ea 100644
--- a/ojluni/src/main/java/java/io/PipedReader.java
+++ b/ojluni/src/main/java/java/io/PipedReader.java
@@ -32,7 +32,7 @@
  * Piped character-input streams.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class PipedReader extends Reader {
@@ -292,6 +292,7 @@
      *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
      *                  {@link #connect(java.io.PipedWriter) unconnected}, closed,
      *                  or an I/O error occurs.
+     * @exception  IndexOutOfBoundsException {@inheritDoc}
      */
     public synchronized int read(char cbuf[], int off, int len)  throws IOException {
         if (!connected) {
diff --git a/ojluni/src/main/java/java/io/PipedWriter.java b/ojluni/src/main/java/java/io/PipedWriter.java
index 46e1455..a4534b8 100644
--- a/ojluni/src/main/java/java/io/PipedWriter.java
+++ b/ojluni/src/main/java/java/io/PipedWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
  * Piped character-output streams.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class PipedWriter extends Writer {
@@ -125,19 +125,25 @@
     }
 
     /**
-     * Writes <code>len</code> characters from the specified character array
-     * starting at offset <code>off</code> to this piped output stream.
+     * Writes {@code len} characters from the specified character array
+     * starting at offset {@code off} to this piped output stream.
      * This method blocks until all the characters are written to the output
      * stream.
      * If a thread was reading data characters from the connected piped input
      * stream, but the thread is no longer alive, then an
-     * <code>IOException</code> is thrown.
+     * {@code IOException} is thrown.
      *
      * @param      cbuf  the data.
      * @param      off   the start offset in the data.
      * @param      len   the number of characters to write.
-     * @exception  IOException  if the pipe is
-     *          <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given array
+     *
+     * @throws  IOException  if the pipe is
+     *          <a href=PipedOutputStream.html#BROKEN><code>broken</code></a>,
      *          {@link #connect(java.io.PipedReader) unconnected}, closed
      *          or an I/O error occurs.
      */
diff --git a/ojluni/src/main/java/java/io/PushbackInputStream.java b/ojluni/src/main/java/java/io/PushbackInputStream.java
index b44848d..d9905c8 100644
--- a/ojluni/src/main/java/java/io/PushbackInputStream.java
+++ b/ojluni/src/main/java/java/io/PushbackInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,9 +28,10 @@
 /**
  * A <code>PushbackInputStream</code> adds
  * functionality to another input stream, namely
- * the  ability to "push back" or "unread"
- * one byte. This is useful in situations where
- * it is  convenient for a fragment of code
+ * the  ability to "push back" or "unread" bytes,
+ * by storing pushed-back bytes in an internal buffer.
+ * This is useful in situations where
+ * it is convenient for a fragment of code
  * to read an indefinite number of data bytes
  * that  are delimited by a particular byte
  * value; after reading the terminating byte,
@@ -46,13 +47,13 @@
  *
  * @author  David Connelly
  * @author  Jonathan Payne
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class PushbackInputStream extends FilterInputStream {
     /**
      * The pushback buffer.
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected byte[] buf;
 
@@ -62,7 +63,7 @@
      * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
      * equal to zero.
      *
-     * @since   JDK1.1
+     * @since   1.1
      */
     protected int pos;
 
@@ -77,16 +78,14 @@
     /**
      * Creates a <code>PushbackInputStream</code>
      * with a pushback buffer of the specified <code>size</code>,
-     * and saves its  argument, the input stream
+     * and saves its argument, the input stream
      * <code>in</code>, for later use. Initially,
-     * there is no pushed-back byte  (the field
-     * <code>pushBack</code> is initialized to
-     * <code>-1</code>).
+     * the pushback buffer is empty.
      *
      * @param  in    the input stream from which bytes will be read.
      * @param  size  the size of the pushback buffer.
      * @exception IllegalArgumentException if {@code size <= 0}
-     * @since  JDK1.1
+     * @since  1.1
      */
     public PushbackInputStream(InputStream in, int size) {
         super(in);
@@ -99,11 +98,9 @@
 
     /**
      * Creates a <code>PushbackInputStream</code>
-     * and saves its  argument, the input stream
+     * with a 1-byte pushback buffer, and saves its argument, the input stream
      * <code>in</code>, for later use. Initially,
-     * there is no pushed-back byte  (the field
-     * <code>pushBack</code> is initialized to
-     * <code>-1</code>).
+     * the pushback buffer is empty.
      *
      * @param   in   the input stream from which bytes will be read.
      */
@@ -224,7 +221,7 @@
      *            buffer for the specified number of bytes,
      *            or this input stream has been closed by
      *            invoking its {@link #close()} method.
-     * @since     JDK1.1
+     * @since     1.1
      */
     public void unread(byte[] b, int off, int len) throws IOException {
         ensureOpen();
@@ -246,7 +243,7 @@
      *            buffer for the specified number of bytes,
      *            or this input stream has been closed by
      *            invoking its {@link #close()} method.
-     * @since     JDK1.1
+     * @since     1.1
      */
     public void unread(byte[] b) throws IOException {
         unread(b, 0, b.length);
@@ -294,10 +291,10 @@
      *
      * @param      n  {@inheritDoc}
      * @return     {@inheritDoc}
-     * @exception  IOException  if the stream does not support seek,
-     *            or the stream has been closed by
-     *            invoking its {@link #close()} method,
-     *            or an I/O error occurs.
+     * @throws     IOException  if the stream has been closed by
+     *             invoking its {@link #close()} method,
+     *             {@code in.skip(n)} throws an IOException,
+     *             or an I/O error occurs.
      * @see        java.io.FilterInputStream#in
      * @see        java.io.InputStream#skip(long n)
      * @since      1.2
diff --git a/ojluni/src/main/java/java/io/PushbackReader.java b/ojluni/src/main/java/java/io/PushbackReader.java
index f918621..85b1854 100644
--- a/ojluni/src/main/java/java/io/PushbackReader.java
+++ b/ojluni/src/main/java/java/io/PushbackReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  * stream.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class PushbackReader extends FilterReader {
@@ -102,6 +102,7 @@
      *             stream has been reached
      *
      * @exception  IOException  If an I/O error occurs
+     * @exception  IndexOutOfBoundsException {@inheritDoc}
      */
     public int read(char cbuf[], int off, int len) throws IOException {
         synchronized (lock) {
@@ -240,13 +241,16 @@
      * Closes the stream and releases any system resources associated with
      * it. Once the stream has been closed, further read(),
      * unread(), ready(), or skip() invocations will throw an IOException.
-     * Closing a previously closed stream has no effect.
+     * Closing a previously closed stream has no effect. This method will block
+     * while there is another thread blocking on the reader.
      *
      * @exception  IOException  If an I/O error occurs
      */
     public void close() throws IOException {
-        super.close();
-        buf = null;
+        synchronized (lock) {
+            super.close();
+            buf = null;
+        }
     }
 
     /**
diff --git a/ojluni/src/main/java/java/io/Serializable.java b/ojluni/src/main/java/java/io/Serializable.java
index 496aef7..eb245cc 100644
--- a/ojluni/src/main/java/java/io/Serializable.java
+++ b/ojluni/src/main/java/java/io/Serializable.java
@@ -26,9 +26,16 @@
 package java.io;
 
 // Android-added: Notes about serialVersionUID, using serialization judiciously, JSON.
+// Android-removed: External links to serialization guidelinenes.
 /**
  * Serializability of a class is enabled by the class implementing the
- * java.io.Serializable interface. Classes that do not implement this
+ * java.io.Serializable interface.
+ *
+ * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
+ * and should be avoided. Untrusted data should be carefully validated.
+ * </strong></p>
+ *
+ * Classes that do not implement this
  * interface will not have any of their state serialized or
  * deserialized.  All subtypes of a serializable class are themselves
  * serializable.  The serialization interface has no methods or fields
@@ -85,9 +92,9 @@
  * correspondingly named fields in the current object.  This handles the case
  * when the class has evolved to add new fields. The method does not need to
  * concern itself with the state belonging to its superclasses or subclasses.
- * State is saved by writing the individual fields to the
- * ObjectOutputStream using the writeObject method or by using the
- * methods for primitive data types supported by DataOutput.
+ * State is restored by reading data from the ObjectInputStream for
+ * the individual fields and making assignments to the appropriate fields
+ * of the object. Reading primitive data types is supported by DataInput.
  *
  * <p>The readObjectNoData method is responsible for initializing the state of
  * the object for its particular class in the event that the serialization
@@ -183,7 +190,7 @@
  * @see java.io.ObjectOutput
  * @see java.io.ObjectInput
  * @see java.io.Externalizable
- * @since   JDK1.1
+ * @since   1.1
  */
 public interface Serializable {
 }
diff --git a/ojluni/src/main/java/java/io/StreamCorruptedException.java b/ojluni/src/main/java/java/io/StreamCorruptedException.java
index 57af82c..22e2216 100644
--- a/ojluni/src/main/java/java/io/StreamCorruptedException.java
+++ b/ojluni/src/main/java/java/io/StreamCorruptedException.java
@@ -30,7 +30,7 @@
  * violates internal consistency checks.
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class StreamCorruptedException extends ObjectStreamException {
 
diff --git a/ojluni/src/main/java/java/io/StreamTokenizer.java b/ojluni/src/main/java/java/io/StreamTokenizer.java
index 3c7c7cc..9de1405 100644
--- a/ojluni/src/main/java/java/io/StreamTokenizer.java
+++ b/ojluni/src/main/java/java/io/StreamTokenizer.java
@@ -59,7 +59,7 @@
  * @author  James Gosling
  * @see     java.io.StreamTokenizer#nextToken()
  * @see     java.io.StreamTokenizer#TT_EOF
- * @since   JDK1.0
+ * @since   1.0
  */
 
 public class StreamTokenizer {
@@ -240,7 +240,7 @@
      * Create a tokenizer that parses the given character stream.
      *
      * @param r  a Reader object providing the input stream.
-     * @since   JDK1.1
+     * @since   1.1
      */
     public StreamTokenizer(Reader r) {
         this();
diff --git a/ojluni/src/main/java/java/io/StringBufferInputStream.java b/ojluni/src/main/java/java/io/StringBufferInputStream.java
index 90c5d4d..f54b725 100644
--- a/ojluni/src/main/java/java/io/StringBufferInputStream.java
+++ b/ojluni/src/main/java/java/io/StringBufferInputStream.java
@@ -37,7 +37,7 @@
  * @author     Arthur van Hoff
  * @see        java.io.ByteArrayInputStream
  * @see        java.io.StringReader
- * @since      JDK1.0
+ * @since      1.0
  * @deprecated This class does not properly convert characters into bytes.  As
  *             of JDK&nbsp;1.1, the preferred way to create a stream from a
  *             string is via the <code>StringReader</code> class.
@@ -108,6 +108,7 @@
      *             <code>-1</code> if there is no more data because the end of
      *             the stream has been reached.
      */
+    @SuppressWarnings("deprecation")
     public synchronized int read(byte b[], int off, int len) {
         if (b == null) {
             throw new NullPointerException();
@@ -127,12 +128,8 @@
         if (len <= 0) {
             return 0;
         }
-        String  s = buffer;
-        int cnt = len;
-        while (--cnt >= 0) {
-            b[off++] = (byte)s.charAt(pos++);
-        }
-
+        buffer.getBytes(pos, pos + len, b, off);
+        pos += len;
         return len;
     }
 
diff --git a/ojluni/src/main/java/java/io/StringReader.java b/ojluni/src/main/java/java/io/StringReader.java
index ce9ff60..9cfe541 100644
--- a/ojluni/src/main/java/java/io/StringReader.java
+++ b/ojluni/src/main/java/java/io/StringReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
  * A character stream whose source is a string.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class StringReader extends Reader {
@@ -84,6 +84,7 @@
      *             stream has been reached
      *
      * @exception  IOException  If an I/O error occurs
+     * @exception  IndexOutOfBoundsException {@inheritDoc}
      */
     public int read(char cbuf[], int off, int len) throws IOException {
         synchronized (lock) {
@@ -141,8 +142,8 @@
      */
     public boolean ready() throws IOException {
         synchronized (lock) {
-        ensureOpen();
-        return true;
+            ensureOpen();
+            return true;
         }
     }
 
@@ -193,9 +194,12 @@
      * Closes the stream and releases any system resources associated with
      * it. Once the stream has been closed, further read(),
      * ready(), mark(), or reset() invocations will throw an IOException.
-     * Closing a previously closed stream has no effect.
+     * Closing a previously closed stream has no effect. This method will block
+     * while there is another thread blocking on the reader.
      */
     public void close() {
-        str = null;
+        synchronized (lock) {
+            str = null;
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/io/StringWriter.java b/ojluni/src/main/java/java/io/StringWriter.java
index c4e5d40..16eed62 100644
--- a/ojluni/src/main/java/java/io/StringWriter.java
+++ b/ojluni/src/main/java/java/io/StringWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,12 @@
  * A character stream that collects its output in a string buffer, which can
  * then be used to construct a string.
  * <p>
- * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
+ * Closing a {@code StringWriter} has no effect. The methods in this class
  * can be called after the stream has been closed without generating an
- * <tt>IOException</tt>.
+ * {@code IOException}.
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class StringWriter extends Writer {
@@ -56,11 +56,11 @@
      * size.
      *
      * @param initialSize
-     *        The number of <tt>char</tt> values that will fit into this buffer
+     *        The number of {@code char} values that will fit into this buffer
      *        before it is automatically expanded
      *
      * @throws IllegalArgumentException
-     *         If <tt>initialSize</tt> is negative
+     *         If {@code initialSize} is negative
      */
     public StringWriter(int initialSize) {
         if (initialSize < 0) {
@@ -83,6 +83,11 @@
      * @param  cbuf  Array of characters
      * @param  off   Offset from which to start writing characters
      * @param  len   Number of characters to write
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given array
      */
     public void write(char cbuf[], int off, int len) {
         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
@@ -107,29 +112,34 @@
      * @param  str  String to be written
      * @param  off  Offset from which to start writing characters
      * @param  len  Number of characters to write
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given string
      */
     public void write(String str, int off, int len)  {
-        buf.append(str.substring(off, off + len));
+        buf.append(str, off, off + len);
     }
 
     /**
      * Appends the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * <p> An invocation of this method of the form {@code out.append(csq)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
      *     out.write(csq.toString()) </pre>
      *
-     * <p> Depending on the specification of <tt>toString</tt> for the
-     * character sequence <tt>csq</tt>, the entire sequence may not be
-     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * <p> Depending on the specification of {@code toString} for the
+     * character sequence {@code csq}, the entire sequence may not be
+     * appended. For instance, invoking the {@code toString} method of a
      * character buffer will return a subsequence whose content depends upon
      * the buffer's position and limit.
      *
      * @param  csq
-     *         The character sequence to append.  If <tt>csq</tt> is
-     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         The character sequence to append.  If {@code csq} is
+     *         {@code null}, then the four characters {@code "null"} are
      *         appended to this writer.
      *
      * @return  This writer
@@ -137,28 +147,27 @@
      * @since  1.5
      */
     public StringWriter append(CharSequence csq) {
-        if (csq == null)
-            write("null");
-        else
-            write(csq.toString());
+        write(String.valueOf(csq));
         return this;
     }
 
     /**
      * Appends a subsequence of the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq, start,
-     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * <p> An invocation of this method of the form
+     * {@code out.append(csq, start, end)} when {@code csq}
+     * is not {@code null}, behaves in
      * exactly the same way as the invocation
      *
-     * <pre>
-     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     * <pre>{@code
+     *     out.write(csq.subSequence(start, end).toString())
+     * }</pre>
      *
      * @param  csq
      *         The character sequence from which a subsequence will be
-     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
-     *         will be appended as if <tt>csq</tt> contained the four
-     *         characters <tt>"null"</tt>.
+     *         appended.  If {@code csq} is {@code null}, then characters
+     *         will be appended as if {@code csq} contained the four
+     *         characters {@code "null"}.
      *
      * @param  start
      *         The index of the first character in the subsequence
@@ -170,22 +179,21 @@
      * @return  This writer
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
-     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
-     *          <tt>csq.length()</tt>
+     *          If {@code start} or {@code end} are negative, {@code start}
+     *          is greater than {@code end}, or {@code end} is greater than
+     *          {@code csq.length()}
      *
      * @since  1.5
      */
     public StringWriter append(CharSequence csq, int start, int end) {
-        CharSequence cs = (csq == null ? "null" : csq);
-        write(cs.subSequence(start, end).toString());
-        return this;
+        if (csq == null) csq = "null";
+        return append(csq.subSequence(start, end));
     }
 
     /**
      * Appends the specified character to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * <p> An invocation of this method of the form {@code out.append(c)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
@@ -226,9 +234,9 @@
     }
 
     /**
-     * Closing a <tt>StringWriter</tt> has no effect. The methods in this
+     * Closing a {@code StringWriter} has no effect. The methods in this
      * class can be called after the stream has been closed without generating
-     * an <tt>IOException</tt>.
+     * an {@code IOException}.
      */
     public void close() throws IOException {
     }
diff --git a/ojluni/src/main/java/java/io/SyncFailedException.java b/ojluni/src/main/java/java/io/SyncFailedException.java
index 7e553a7..dc1228ad 100644
--- a/ojluni/src/main/java/java/io/SyncFailedException.java
+++ b/ojluni/src/main/java/java/io/SyncFailedException.java
@@ -31,7 +31,7 @@
  * @author  Ken Arnold
  * @see     java.io.FileDescriptor#sync
  * @see     java.io.IOException
- * @since   JDK1.1
+ * @since   1.1
  */
 public class SyncFailedException extends IOException {
     private static final long serialVersionUID = -2353342684412443330L;
diff --git a/ojluni/src/main/java/java/io/UTFDataFormatException.java b/ojluni/src/main/java/java/io/UTFDataFormatException.java
index 422d28b..88a1cf7 100644
--- a/ojluni/src/main/java/java/io/UTFDataFormatException.java
+++ b/ojluni/src/main/java/java/io/UTFDataFormatException.java
@@ -40,7 +40,7 @@
  * @see     java.io.DataInput
  * @see     java.io.DataInputStream#readUTF(java.io.DataInput)
  * @see     java.io.IOException
- * @since   JDK1.0
+ * @since   1.0
  */
 public
 class UTFDataFormatException extends IOException {
diff --git a/ojluni/src/main/java/java/io/UnsupportedEncodingException.java b/ojluni/src/main/java/java/io/UnsupportedEncodingException.java
index b59f9c3..48b2224 100644
--- a/ojluni/src/main/java/java/io/UnsupportedEncodingException.java
+++ b/ojluni/src/main/java/java/io/UnsupportedEncodingException.java
@@ -28,7 +28,7 @@
  * The Character Encoding is not supported.
  *
  * @author  Asmus Freytag
- * @since   JDK1.1
+ * @since   1.1
  */
 public class UnsupportedEncodingException
     extends IOException
diff --git a/ojluni/src/main/java/java/io/WriteAbortedException.java b/ojluni/src/main/java/java/io/WriteAbortedException.java
index c39950d..202575c 100644
--- a/ojluni/src/main/java/java/io/WriteAbortedException.java
+++ b/ojluni/src/main/java/java/io/WriteAbortedException.java
@@ -41,7 +41,7 @@
  * method, as well as the aforementioned "legacy field."
  *
  * @author  unascribed
- * @since   JDK1.1
+ * @since   1.1
  */
 public class WriteAbortedException extends ObjectStreamException {
     private static final long serialVersionUID = -3326426625597282442L;
diff --git a/ojluni/src/main/java/java/util/BitSet.java b/ojluni/src/main/java/java/util/BitSet.java
index 261a77c..c72970d 100644
--- a/ojluni/src/main/java/java/util/BitSet.java
+++ b/ojluni/src/main/java/java/util/BitSet.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.LongBuffer;
+import java.util.function.IntConsumer;
 import java.util.stream.IntStream;
 import java.util.stream.StreamSupport;
 
@@ -60,7 +61,7 @@
  * @author  Arthur van Hoff
  * @author  Michael McCloskey
  * @author  Martin Buchholz
- * @since   JDK1.0
+ * @since   1.0
  */
 public class BitSet implements Cloneable, java.io.Serializable {
     /*
@@ -68,9 +69,9 @@
      * a long, which consists of 64 bits, requiring 6 address bits.
      * The choice of word size is determined purely by performance concerns.
      */
-    private final static int ADDRESS_BITS_PER_WORD = 6;
-    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
-    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
+    private static final int ADDRESS_BITS_PER_WORD = 6;
+    private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+    private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1;
 
     /* Used to shift left or right for a partial word mask */
     private static final long WORD_MASK = 0xffffffffffffffffL;
@@ -437,7 +438,7 @@
      *
      * @param  bitIndex a bit index
      * @throws IndexOutOfBoundsException if the specified index is negative
-     * @since  JDK1.0
+     * @since  1.0
      */
     public void set(int bitIndex) {
         if (bitIndex < 0)
@@ -533,7 +534,7 @@
      *
      * @param  bitIndex the index of the bit to be cleared
      * @throws IndexOutOfBoundsException if the specified index is negative
-     * @since  JDK1.0
+     * @since  1.0
      */
     public void clear(int bitIndex) {
         if (bitIndex < 0)
@@ -1209,40 +1210,186 @@
      * is the number of bits in the set state, equal to the value
      * returned by the {@link #cardinality()} method.
      *
-     * <p>The bit set must remain constant during the execution of the
-     * terminal stream operation.  Otherwise, the result of the terminal
-     * stream operation is undefined.
+     * <p>The stream binds to this bit set when the terminal stream operation
+     * commences (specifically, the spliterator for the stream is
+     * <a href="Spliterator.html#binding"><em>late-binding</em></a>).  If the
+     * bit set is modified during that operation then the result is undefined.
      *
      * @return a stream of integers representing set indices
      * @since 1.8
      */
     public IntStream stream() {
-        class BitSetIterator implements PrimitiveIterator.OfInt {
-            int next = nextSetBit(0);
+        class BitSetSpliterator implements Spliterator.OfInt {
+            private int index; // current bit index for a set bit
+            private int fence; // -1 until used; then one past last bit index
+            private int est;   // size estimate
+            private boolean root; // true if root and not split
+            // root == true then size estimate is accurate
+            // index == -1 or index >= fence if fully traversed
+            // Special case when the max bit set is Integer.MAX_VALUE
 
-            @Override
-            public boolean hasNext() {
-                return next != -1;
+            BitSetSpliterator(int origin, int fence, int est, boolean root) {
+                this.index = origin;
+                this.fence = fence;
+                this.est = est;
+                this.root = root;
+            }
+
+            private int getFence() {
+                int hi;
+                if ((hi = fence) < 0) {
+                    // Round up fence to maximum cardinality for allocated words
+                    // This is sufficient and cheap for sequential access
+                    // When splitting this value is lowered
+                    hi = fence = (wordsInUse >= wordIndex(Integer.MAX_VALUE))
+                                 ? Integer.MAX_VALUE
+                                 : wordsInUse << ADDRESS_BITS_PER_WORD;
+                    est = cardinality();
+                    index = nextSetBit(0);
+                }
+                return hi;
             }
 
             @Override
-            public int nextInt() {
-                if (next != -1) {
-                    int ret = next;
-                    next = nextSetBit(next+1);
-                    return ret;
-                } else {
-                    throw new NoSuchElementException();
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                int hi = getFence();
+                int i = index;
+                if (i < 0 || i >= hi) {
+                    // Check if there is a final bit set for Integer.MAX_VALUE
+                    if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) {
+                        index = -1;
+                        action.accept(Integer.MAX_VALUE);
+                        return true;
+                    }
+                    return false;
+                }
+
+                index = nextSetBit(i + 1, wordIndex(hi - 1));
+                action.accept(i);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                int hi = getFence();
+                int i = index;
+                index = -1;
+
+                if (i >= 0 && i < hi) {
+                    action.accept(i++);
+
+                    int u = wordIndex(i);      // next lower word bound
+                    int v = wordIndex(hi - 1); // upper word bound
+
+                    words_loop:
+                    for (; u <= v && i <= hi; u++, i = u << ADDRESS_BITS_PER_WORD) {
+                        long word = words[u] & (WORD_MASK << i);
+                        while (word != 0) {
+                            i = (u << ADDRESS_BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+                            if (i >= hi) {
+                                // Break out of outer loop to ensure check of
+                                // Integer.MAX_VALUE bit set
+                                break words_loop;
+                            }
+
+                            // Flip the set bit
+                            word &= ~(1L << i);
+
+                            action.accept(i);
+                        }
+                    }
+                }
+
+                // Check if there is a final bit set for Integer.MAX_VALUE
+                if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) {
+                    action.accept(Integer.MAX_VALUE);
                 }
             }
-        }
 
-        return StreamSupport.intStream(
-                () -> Spliterators.spliterator(
-                        new BitSetIterator(), cardinality(),
-                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
-                Spliterator.SIZED | Spliterator.SUBSIZED |
-                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
-                false);
+            @Override
+            public OfInt trySplit() {
+                int hi = getFence();
+                int lo = index;
+                if (lo < 0) {
+                    return null;
+                }
+
+                // Lower the fence to be the upper bound of last bit set
+                // The index is the first bit set, thus this spliterator
+                // covers one bit and cannot be split, or two or more
+                // bits
+                hi = fence = (hi < Integer.MAX_VALUE || !get(Integer.MAX_VALUE))
+                        ? previousSetBit(hi - 1) + 1
+                        : Integer.MAX_VALUE;
+
+                // Find the mid point
+                int mid = (lo + hi) >>> 1;
+                if (lo >= mid) {
+                    return null;
+                }
+
+                // Raise the index of this spliterator to be the next set bit
+                // from the mid point
+                index = nextSetBit(mid, wordIndex(hi - 1));
+                root = false;
+
+                // Don't lower the fence (mid point) of the returned spliterator,
+                // traversal or further splitting will do that work
+                return new BitSetSpliterator(lo, mid, est >>>= 1, false);
+            }
+
+            @Override
+            public long estimateSize() {
+                getFence(); // force init
+                return est;
+            }
+
+            @Override
+            public int characteristics() {
+                // Only sized when root and not split
+                return (root ? Spliterator.SIZED : 0) |
+                    Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED;
+            }
+
+            @Override
+            public Comparator<? super Integer> getComparator() {
+                return null;
+            }
+        }
+        return StreamSupport.intStream(new BitSetSpliterator(0, -1, 0, true), false);
     }
+
+    /**
+     * Returns the index of the first bit that is set to {@code true}
+     * that occurs on or after the specified starting index and up to and
+     * including the specified word index
+     * If no such bit exists then {@code -1} is returned.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @param  toWordIndex the last word index to check (inclusive)
+     * @return the index of the next set bit, or {@code -1} if there
+     *         is no such bit
+     */
+    private int nextSetBit(int fromIndex, int toWordIndex) {
+        int u = wordIndex(fromIndex);
+        // Check if out of bounds
+        if (u > toWordIndex)
+            return -1;
+
+        long word = words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            // Check if out of bounds
+            if (++u > toWordIndex)
+                return -1;
+            word = words[u];
+        }
+    }
+
 }
diff --git a/ojluni/src/main/java/java/util/StringJoiner.java b/ojluni/src/main/java/java/util/StringJoiner.java
index 07ccbcc..27e2fb2 100644
--- a/ojluni/src/main/java/java/util/StringJoiner.java
+++ b/ojluni/src/main/java/java/util/StringJoiner.java
@@ -67,16 +67,15 @@
     private final String delimiter;
     private final String suffix;
 
-    /** Contains all the string components added so far. */
-    private String[] elts;
+    /*
+     * StringBuilder value -- at any time, the characters constructed from the
+     * prefix, the added element separated by the delimiter, but without the
+     * suffix, so that we can more easily add elements without having to jigger
+     * the suffix each time.
+     */
+    private StringBuilder value;
 
-    /** The number of string components added so far. */
-    private int size;
-
-    /** Total length in chars so far, excluding prefix and suffix. */
-    private int len;
-
-    /**
+    /*
      * When overridden by the user to be non-null via {@link setEmptyValue}, the
      * string returned by toString() when no elements have yet been added.
      * When null, prefix + suffix is used as the empty value.
@@ -125,6 +124,7 @@
         this.prefix = prefix.toString();
         this.delimiter = delimiter.toString();
         this.suffix = suffix.toString();
+        this.emptyValue = this.prefix + this.suffix;
     }
 
     /**
@@ -147,12 +147,6 @@
         return this;
     }
 
-    private static int getChars(String s, char[] chars, int start) {
-        int len = s.length();
-        s.getChars(0, len, chars, start);
-        return len;
-    }
-
     /**
      * Returns the current value, consisting of the {@code prefix}, the values
      * added so far separated by the {@code delimiter}, and the {@code suffix},
@@ -163,28 +157,19 @@
      */
     @Override
     public String toString() {
-        final String[] elts = this.elts;
-        if (elts == null && emptyValue != null) {
+        if (value == null) {
             return emptyValue;
-        }
-        final int size = this.size;
-        final int addLen = prefix.length() + suffix.length();
-        if (addLen == 0) {
-            compactElts();
-            return size == 0 ? "" : elts[0];
-        }
-        final String delimiter = this.delimiter;
-        final char[] chars = new char[len + addLen];
-        int k = getChars(prefix, chars, 0);
-        if (size > 0) {
-            k += getChars(elts[0], chars, k);
-            for (int i = 1; i < size; i++) {
-                k += getChars(delimiter, chars, k);
-                k += getChars(elts[i], chars, k);
+        } else {
+            if (suffix.equals("")) {
+                return value.toString();
+            } else {
+                int initialLength = value.length();
+                String result = value.append(suffix).toString();
+                // reset value to pre-append initialLength
+                value.setLength(initialLength);
+                return result;
             }
         }
-        k += getChars(suffix, chars, k);
-        return new String(chars);
     }
 
     /**
@@ -196,16 +181,7 @@
      * @return a reference to this {@code StringJoiner}
      */
     public StringJoiner add(CharSequence newElement) {
-        final String elt = String.valueOf(newElement);
-        if (elts == null) {
-            elts = new String[8];
-        } else {
-            if (size == elts.length)
-                elts = Arrays.copyOf(elts, 2 * size);
-            len += delimiter.length();
-        }
-        len += elt.length();
-        elts[size++] = elt;
+        prepareBuilder().append(newElement);
         return this;
     }
 
@@ -230,25 +206,24 @@
      */
     public StringJoiner merge(StringJoiner other) {
         Objects.requireNonNull(other);
-        if (other.elts == null) {
-            return this;
+        if (other.value != null) {
+            final int length = other.value.length();
+            // lock the length so that we can seize the data to be appended
+            // before initiate copying to avoid interference, especially when
+            // merge 'this'
+            StringBuilder builder = prepareBuilder();
+            builder.append(other.value, other.prefix.length(), length);
         }
-        other.compactElts();
-        return add(other.elts[0]);
+        return this;
     }
 
-    private void compactElts() {
-        if (size > 1) {
-            final char[] chars = new char[len];
-            int i = 1, k = getChars(elts[0], chars, 0);
-            do {
-                k += getChars(delimiter, chars, k);
-                k += getChars(elts[i], chars, k);
-                elts[i] = null;
-            } while (++i < size);
-            size = 1;
-            elts[0] = new String(chars);
+    private StringBuilder prepareBuilder() {
+        if (value != null) {
+            value.append(delimiter);
+        } else {
+            value = new StringBuilder().append(prefix);
         }
+        return value;
     }
 
     /**
@@ -262,7 +237,10 @@
      * @return the length of the current value of {@code StringJoiner}
      */
     public int length() {
-        return (size == 0 && emptyValue != null) ? emptyValue.length() :
-            len + prefix.length() + suffix.length();
+        // Remember that we never actually append the suffix unless we return
+        // the full (present) value or some sub-string or length of it, so that
+        // we can add on more if we need to.
+        return (value != null ? value.length() + suffix.length() :
+                emptyValue.length());
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index a206867..e4d2235 100644
--- a/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -245,7 +245,8 @@
                 Future<T> f = futures.get(i);
                 if (!f.isDone()) {
                     try { f.get(); }
-                    catch (CancellationException | ExecutionException ignore) {}
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
                 }
             }
             return futures;
@@ -282,7 +283,8 @@
                 Future<T> f = futures.get(j);
                 if (!f.isDone()) {
                     try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
-                    catch (CancellationException | ExecutionException ignore) {}
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
                     catch (TimeoutException timedOut) {
                         break timedOut;
                     }
diff --git a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index dced5a4..96a60b3 100644
--- a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -46,8 +46,10 @@
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -72,24 +74,17 @@
  * generally decreases throughput but reduces variability and avoids
  * starvation.
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
+ * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
  */
 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
         implements BlockingQueue<E>, java.io.Serializable {
 
-    /*
-     * Much of the implementation mechanics, especially the unusual
-     * nested loops, are shared and co-maintained with ArrayDeque.
-     */
-
     /**
      * Serialization ID. This class relies on default serialization
      * even for the items array, which is default-serialized, even if
@@ -134,21 +129,10 @@
     // Internal helper methods
 
     /**
-     * Increments i, mod modulus.
-     * Precondition and postcondition: 0 <= i < modulus.
+     * Circularly decrements array index i.
      */
-    static final int inc(int i, int modulus) {
-        if (++i >= modulus) i = 0;
-        return i;
-    }
-
-    /**
-     * Decrements i, mod modulus.
-     * Precondition and postcondition: 0 <= i < modulus.
-     */
-    static final int dec(int i, int modulus) {
-        if (--i < 0) i = modulus - 1;
-        return i;
+    final int dec(int i) {
+        return ((i == 0) ? items.length : i) - 1;
     }
 
     /**
@@ -160,24 +144,14 @@
     }
 
     /**
-     * Returns element at array index i.
-     * This is a slight abuse of generics, accepted by javac.
-     */
-    @SuppressWarnings("unchecked")
-    static <E> E itemAt(Object[] items, int i) {
-        return (E) items[i];
-    }
-
-    /**
      * Inserts element at current put position, advances, and signals.
      * Call only when holding lock.
      */
-    private void enqueue(E e) {
-        // assert lock.isHeldByCurrentThread();
+    private void enqueue(E x) {
         // assert lock.getHoldCount() == 1;
         // assert items[putIndex] == null;
         final Object[] items = this.items;
-        items[putIndex] = e;
+        items[putIndex] = x;
         if (++putIndex == items.length) putIndex = 0;
         count++;
         notEmpty.signal();
@@ -188,19 +162,18 @@
      * Call only when holding lock.
      */
     private E dequeue() {
-        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[takeIndex] != null;
         final Object[] items = this.items;
         @SuppressWarnings("unchecked")
-        E e = (E) items[takeIndex];
+        E x = (E) items[takeIndex];
         items[takeIndex] = null;
         if (++takeIndex == items.length) takeIndex = 0;
         count--;
         if (itrs != null)
             itrs.elementDequeued();
         notFull.signal();
-        return e;
+        return x;
     }
 
     /**
@@ -209,7 +182,6 @@
      * Call only when holding lock.
      */
     void removeAt(final int removeIndex) {
-        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[removeIndex] != null;
         // assert removeIndex >= 0 && removeIndex < items.length;
@@ -295,7 +267,6 @@
         final ReentrantLock lock = this.lock;
         lock.lock(); // Lock only for visibility, not mutual exclusion
         try {
-            final Object[] items = this.items;
             int i = 0;
             try {
                 for (E e : c)
@@ -510,16 +481,15 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                for (int i = takeIndex, end = putIndex,
-                         to = (i < end) ? end : items.length;
-                     ; i = 0, to = end) {
-                    for (; i < to; i++)
-                        if (o.equals(items[i])) {
-                            removeAt(i);
-                            return true;
-                        }
-                    if (to == end) break;
-                }
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i])) {
+                        removeAt(i);
+                        return true;
+                    }
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
             }
             return false;
         } finally {
@@ -542,14 +512,13 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                for (int i = takeIndex, end = putIndex,
-                         to = (i < end) ? end : items.length;
-                     ; i = 0, to = end) {
-                    for (; i < to; i++)
-                        if (o.equals(items[i]))
-                            return true;
-                    if (to == end) break;
-                }
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i]))
+                        return true;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
             }
             return false;
         } finally {
@@ -656,9 +625,15 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int k;
-            if ((k = count) > 0) {
-                circularClear(items, takeIndex, putIndex);
+            int k = count;
+            if (k > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    items[i] = null;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
                 takeIndex = putIndex;
                 count = 0;
                 if (itrs != null)
@@ -672,20 +647,6 @@
     }
 
     /**
-     * Nulls out slots starting at array index i, upto index end.
-     * Condition i == end means "full" - the entire array is cleared.
-     */
-    private static void circularClear(Object[] items, int i, int end) {
-        // assert 0 <= i && i < items.length;
-        // assert 0 <= end && end < items.length;
-        for (int to = (i < end) ? end : items.length;
-             ; i = 0, to = end) {
-            for (; i < to; i++) items[i] = null;
-            if (to == end) break;
-        }
-    }
-
-    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
@@ -717,8 +678,8 @@
             try {
                 while (i < n) {
                     @SuppressWarnings("unchecked")
-                    E e = (E) items[take];
-                    c.add(e);
+                    E x = (E) items[take];
+                    c.add(x);
                     items[take] = null;
                     if (++take == items.length) take = 0;
                     i++;
@@ -847,7 +808,7 @@
          * there is known to be at least one iterator to collect
          */
         void doSomeSweeping(boolean tryHarder) {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             // assert head != null;
             int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
             Node o, p;
@@ -903,7 +864,7 @@
          * Adds a new iterator to the linked list of tracked iterators.
          */
         void register(Itr itr) {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             head = new Node(itr, head);
         }
 
@@ -913,7 +874,7 @@
          * Notifies all iterators, and expunges any that are now stale.
          */
         void takeIndexWrapped() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             cycles++;
             for (Node o = null, p = head; p != null;) {
                 final Itr it = p.get();
@@ -970,7 +931,7 @@
          * clears all weak refs, and unlinks the itrs datastructure.
          */
         void queueIsEmpty() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             for (Node p = head; p != null; p = p.next) {
                 Itr it = p.get();
                 if (it != null) {
@@ -986,7 +947,7 @@
          * Called whenever an element has been dequeued (at takeIndex).
          */
         void elementDequeued() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             if (count == 0)
                 queueIsEmpty();
             else if (takeIndex == 0)
@@ -1011,11 +972,6 @@
      * expected element to remove, in lastItem.  Yes, we may fail to
      * remove lastItem from the queue if it moved due to an interleaved
      * interior remove while in detached mode.
-     *
-     * Method forEachRemaining, added in Java 8, is treated similarly
-     * to hasNext returning false, in that we switch to detached mode,
-     * but we regard it as an even stronger request to "close" this
-     * iteration, and don't bother supporting subsequent remove().
      */
     private class Itr implements Iterator<E> {
         /** Index to look for new nextItem; NONE at end */
@@ -1052,6 +1008,7 @@
         private static final int DETACHED = -3;
 
         Itr() {
+            // assert lock.getHoldCount() == 0;
             lastRet = NONE;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1084,12 +1041,12 @@
         }
 
         boolean isDetached() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             return prevTakeIndex < 0;
         }
 
         private int incCursor(int index) {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             if (++index == items.length) index = 0;
             if (index == putIndex) index = NONE;
             return index;
@@ -1114,7 +1071,7 @@
          * operation on this iterator.  Call only from iterating thread.
          */
         private void incorporateDequeues() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             // assert itrs != null;
             // assert !isDetached();
             // assert count > 0;
@@ -1128,7 +1085,7 @@
                 final int len = items.length;
                 // how far takeIndex has advanced since the previous
                 // operation of this iterator
-                long dequeues = (long) (cycles - prevCycles) * len
+                long dequeues = (cycles - prevCycles) * len
                     + (takeIndex - prevTakeIndex);
 
                 // Check indices for invalidation
@@ -1157,7 +1114,7 @@
          */
         private void detach() {
             // Switch to detached mode
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             // assert cursor == NONE;
             // assert nextIndex < 0;
             // assert lastRet < 0 || nextItem == null;
@@ -1177,6 +1134,7 @@
          * triggered by queue modifications.
          */
         public boolean hasNext() {
+            // assert lock.getHoldCount() == 0;
             if (nextItem != null)
                 return true;
             noNext();
@@ -1206,8 +1164,9 @@
         }
 
         public E next() {
-            final E e = nextItem;
-            if (e == null)
+            // assert lock.getHoldCount() == 0;
+            final E x = nextItem;
+            if (x == null)
                 throw new NoSuchElementException();
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1225,48 +1184,17 @@
                 } else {
                     nextIndex = NONE;
                     nextItem = null;
-                    if (lastRet == REMOVED) detach();
                 }
             } finally {
                 lock.unlock();
             }
-            return e;
-        }
-
-        public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
-            lock.lock();
-            try {
-                final E e = nextItem;
-                if (e == null) return;
-                if (!isDetached())
-                    incorporateDequeues();
-                action.accept(e);
-                if (isDetached() || cursor < 0) return;
-                final Object[] items = ArrayBlockingQueue.this.items;
-                for (int i = cursor, end = putIndex,
-                         to = (i < end) ? end : items.length;
-                     ; i = 0, to = end) {
-                    for (; i < to; i++)
-                        action.accept(itemAt(items, i));
-                    if (to == end) break;
-                }
-            } finally {
-                // Calling forEachRemaining is a strong hint that this
-                // iteration is surely over; supporting remove() after
-                // forEachRemaining() is more trouble than it's worth
-                cursor = nextIndex = lastRet = NONE;
-                nextItem = lastItem = null;
-                detach();
-                lock.unlock();
-            }
+            return x;
         }
 
         public void remove() {
+            // assert lock.getHoldCount() == 0;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
-            // assert lock.getHoldCount() == 1;
             try {
                 if (!isDetached())
                     incorporateDequeues(); // might update lastRet or detach
@@ -1304,7 +1232,7 @@
          * from next(), as promised by returning true from hasNext().
          */
         void shutdown() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             cursor = NONE;
             if (nextIndex >= 0)
                 nextIndex = REMOVED;
@@ -1332,7 +1260,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean removedAt(int removedIndex) {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             if (isDetached())
                 return true;
 
@@ -1357,7 +1285,7 @@
                 }
                 else if (x > removedDistance) {
                     // assert cursor != prevTakeIndex;
-                    this.cursor = cursor = dec(cursor, len);
+                    this.cursor = cursor = dec(cursor);
                 }
             }
             int lastRet = this.lastRet;
@@ -1366,7 +1294,7 @@
                 if (x == removedDistance)
                     this.lastRet = lastRet = REMOVED;
                 else if (x > removedDistance)
-                    this.lastRet = lastRet = dec(lastRet, len);
+                    this.lastRet = lastRet = dec(lastRet);
             }
             int nextIndex = this.nextIndex;
             if (nextIndex >= 0) {
@@ -1374,7 +1302,7 @@
                 if (x == removedDistance)
                     this.nextIndex = nextIndex = REMOVED;
                 else if (x > removedDistance)
-                    this.nextIndex = nextIndex = dec(nextIndex, len);
+                    this.nextIndex = nextIndex = dec(nextIndex);
             }
             if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
                 this.prevTakeIndex = DETACHED;
@@ -1389,7 +1317,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean takeIndexWrapped() {
-            // assert lock.isHeldByCurrentThread();
+            // assert lock.getHoldCount() == 1;
             if (isDetached())
                 return true;
             if (itrs.cycles - prevCycles > 1) {
@@ -1438,197 +1366,4 @@
                     Spliterator.CONCURRENT));
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            if (count > 0) {
-                final Object[] items = this.items;
-                for (int i = takeIndex, end = putIndex,
-                         to = (i < end) ? end : items.length;
-                     ; i = 0, to = end) {
-                    for (; i < to; i++)
-                        action.accept(itemAt(items, i));
-                    if (to == end) break;
-                }
-            }
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
-
-    /** Implementation of bulk remove methods. */
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            if (itrs == null) { // check for active iterators
-                if (count > 0) {
-                    final Object[] items = this.items;
-                    // Optimize for initial run of survivors
-                    for (int i = takeIndex, end = putIndex,
-                             to = (i < end) ? end : items.length;
-                         ; i = 0, to = end) {
-                        for (; i < to; i++)
-                            if (filter.test(itemAt(items, i)))
-                                return bulkRemoveModified(filter, i);
-                        if (to == end) break;
-                    }
-                }
-                return false;
-            }
-        } finally {
-            lock.unlock();
-        }
-        // Active iterators are too hairy!
-        // Punting (for now) to the slow n^2 algorithm ...
-        return super.removeIf(filter);
-    }
-
-    // A tiny bit set implementation
-
-    private static long[] nBits(int n) {
-        return new long[((n - 1) >> 6) + 1];
-    }
-    private static void setBit(long[] bits, int i) {
-        bits[i >> 6] |= 1L << i;
-    }
-    private static boolean isClear(long[] bits, int i) {
-        return (bits[i >> 6] & (1L << i)) == 0;
-    }
-
-    /**
-     * Returns circular distance from i to j, disambiguating i == j to
-     * items.length; never returns 0.
-     */
-    private int distanceNonEmpty(int i, int j) {
-        if ((j -= i) <= 0) j += items.length;
-        return j;
-    }
-
-    /**
-     * Helper for bulkRemove, in case of at least one deletion.
-     * Tolerate predicates that reentrantly access the collection for
-     * read (but not write), so traverse once to find elements to
-     * delete, a second pass to physically expunge.
-     *
-     * @param beg valid index of first element to be deleted
-     */
-    private boolean bulkRemoveModified(
-        Predicate<? super E> filter, final int beg) {
-        final Object[] es = items;
-        final int capacity = items.length;
-        final int end = putIndex;
-        final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
-        deathRow[0] = 1L;   // set bit 0
-        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
-             ; i = 0, to = end, k -= capacity) {
-            for (; i < to; i++)
-                if (filter.test(itemAt(es, i)))
-                    setBit(deathRow, i - k);
-            if (to == end) break;
-        }
-        // a two-finger traversal, with hare i reading, tortoise w writing
-        int w = beg;
-        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
-             ; w = 0) { // w rejoins i on second leg
-            // In this loop, i and w are on the same leg, with i > w
-            for (; i < to; i++)
-                if (isClear(deathRow, i - k))
-                    es[w++] = es[i];
-            if (to == end) break;
-            // In this loop, w is on the first leg, i on the second
-            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
-                if (isClear(deathRow, i - k))
-                    es[w++] = es[i];
-            if (i >= to) {
-                if (w == capacity) w = 0; // "corner" case
-                break;
-            }
-        }
-        count -= distanceNonEmpty(w, end);
-        circularClear(es, putIndex = w, end);
-        return true;
-    }
-
-    /** debugging */
-    void checkInvariants() {
-        // meta-assertions
-        // assert lock.isHeldByCurrentThread();
-        if (!invariantsSatisfied()) {
-            String detail = String.format(
-                "takeIndex=%d putIndex=%d count=%d capacity=%d items=%s",
-                takeIndex, putIndex, count, items.length,
-                Arrays.toString(items));
-            System.err.println(detail);
-            throw new AssertionError(detail);
-        }
-    }
-
-    private boolean invariantsSatisfied() {
-        // Unlike ArrayDeque, we have a count field but no spare slot.
-        // We prefer ArrayDeque's strategy (and the names of its fields!),
-        // but our field layout is baked into the serial form, and so is
-        // too annoying to change.
-        //
-        // putIndex == takeIndex must be disambiguated by checking count.
-        int capacity = items.length;
-        return capacity > 0
-            && items.getClass() == Object[].class
-            && (takeIndex | putIndex | count) >= 0
-            && takeIndex <  capacity
-            && putIndex  <  capacity
-            && count     <= capacity
-            && (putIndex - takeIndex - count) % capacity == 0
-            && (count == 0 || items[takeIndex] != null)
-            && (count == capacity || items[putIndex] == null)
-            && (count == 0 || items[dec(putIndex, capacity)] != null);
-    }
-
-    /**
-     * Reconstitutes this queue from a stream (that is, deserializes it).
-     *
-     * @param s the stream
-     * @throws ClassNotFoundException if the class of a serialized object
-     *         could not be found
-     * @throws java.io.InvalidObjectException if invariants are violated
-     * @throws java.io.IOException if an I/O error occurs
-     */
-    private void readObject(java.io.ObjectInputStream s)
-        throws java.io.IOException, ClassNotFoundException {
-
-        // Read in items array and various fields
-        s.defaultReadObject();
-
-        if (!invariantsSatisfied())
-            throw new java.io.InvalidObjectException("invariants violated");
-    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
index 8043510..290fee1 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -39,6 +39,10 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+// BEGIN android-note
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
 /**
  * A {@link Deque} that additionally supports blocking operations that wait
  * for the deque to become non-empty when retrieving an element, and wait for
@@ -53,69 +57,69 @@
  * and the fourth blocks for only a given maximum time limit before giving
  * up.  These methods are summarized in the following table:
  *
- * <table class="plain">
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
  * <caption>Summary of BlockingDeque methods</caption>
  *  <tr>
- *    <th id="First" colspan="5"> First Element (Head)</th>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
  *  </tr>
  *  <tr>
  *    <td></td>
- *    <th id="FThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
- *    <th id="FValue" style="font-weight:normal; font-style: italic">Special value</th>
- *    <th id="FBlock" style="font-weight:normal; font-style: italic">Blocks</th>
- *    <th id="FTimes" style="font-weight:normal; font-style: italic">Times out</th>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
  *  </tr>
  *  <tr>
- *    <th id="FInsert" style="text-align:left">Insert</th>
- *    <td headers="First FInsert FThrow">{@link #addFirst(Object) addFirst(e)}</td>
- *    <td headers="First FInsert FValue">{@link #offerFirst(Object) offerFirst(e)}</td>
- *    <td headers="First FInsert FBlock">{@link #putFirst(Object) putFirst(e)}</td>
- *    <td headers="First FInsert FTimes">{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addFirst addFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td>{@link #putFirst putFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th id="FRemove" style="text-align:left">Remove</th>
- *    <td headers="First FRemove FThrow">{@link #removeFirst() removeFirst()}</td>
- *    <td headers="First FRemove FValue">{@link #pollFirst() pollFirst()}</td>
- *    <td headers="First FRemove FBlock">{@link #takeFirst() takeFirst()}</td>
- *    <td headers="First FRemove FTimes">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *    <td>{@link #pollFirst pollFirst()}</td>
+ *    <td>{@link #takeFirst takeFirst()}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th id="FExamine" style="text-align:left">Examine</th>
- *    <td headers="First FExamine FThrow">{@link #getFirst() getFirst()}</td>
- *    <td headers="First FExamine FValue">{@link #peekFirst() peekFirst()}</td>
- *    <td headers="First FExamine FBlock" style="font-style:italic">not applicable</td>
- *    <td headers="First FExamine FTimes" style="font-style:italic">not applicable</td>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getFirst getFirst()}</td>
+ *    <td>{@link #peekFirst peekFirst()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
  *  </tr>
  *  <tr>
- *    <th id="Last" colspan="5"> Last Element (Tail)</th>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
  *  </tr>
  *  <tr>
  *    <td></td>
- *    <th id="LThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
- *    <th id="LValue" style="font-weight:normal; font-style: italic">Special value</th>
- *    <th id="LBlock" style="font-weight:normal; font-style: italic">Blocks</th>
- *    <th id="LTimes" style="font-weight:normal; font-style: italic">Times out</th>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
  *  </tr>
  *  <tr>
- *    <th id="LInsert" style="text-align:left">Insert</th>
- *    <td headers="Last LInsert LThrow">{@link #addLast(Object) addLast(e)}</td>
- *    <td headers="Last LInsert LValue">{@link #offerLast(Object) offerLast(e)}</td>
- *    <td headers="Last LInsert LBlock">{@link #putLast(Object) putLast(e)}</td>
- *    <td headers="Last LInsert LTimes">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addLast addLast(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td>{@link #putLast putLast(e)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th id="LRemove" style="text-align:left">Remove</th>
- *    <td headers="Last LRemove LThrow">{@link #removeLast() removeLast()}</td>
- *    <td headers="Last LRemove LValue">{@link #pollLast() pollLast()}</td>
- *    <td headers="Last LRemove LBlock">{@link #takeLast() takeLast()}</td>
- *    <td headers="Last LRemove LTimes">{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeLast() removeLast()}</td>
+ *    <td>{@link #pollLast() pollLast()}</td>
+ *    <td>{@link #takeLast takeLast()}</td>
+ *    <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th id="LExamine" style="text-align:left">Examine</th>
- *    <td headers="Last LExamine LThrow">{@link #getLast() getLast()}</td>
- *    <td headers="Last LExamine LValue">{@link #peekLast() peekLast()}</td>
- *    <td headers="Last LExamine LBlock" style="font-style:italic">not applicable</td>
- *    <td headers="Last LExamine LTimes" style="font-style:italic">not applicable</td>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getLast getLast()}</td>
+ *    <td>{@link #peekLast peekLast()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
  *  </tr>
  * </table>
  *
@@ -128,55 +132,60 @@
  * {@code BlockingQueue} interface are precisely equivalent to
  * {@code BlockingDeque} methods as indicated in the following table:
  *
- * <table class="plain">
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
  * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
  *  <tr>
- *    <td></td>
- *    <th id="BQueue"> {@code BlockingQueue} Method</th>
- *    <th id="BDeque"> Equivalent {@code BlockingDeque} Method</th>
+ *    <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
  *  </tr>
  *  <tr>
- *    <th id="Insert" rowspan="4" style="text-align:left; vertical-align:top">Insert</th>
- *    <th id="add" style="font-weight:normal; text-align:left">{@link #add(Object) add(e)}</th>
- *    <td headers="Insert BDeque add">{@link #addLast(Object) addLast(e)}</td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
  *  </tr>
  *  <tr>
- *    <th id="offer1" style="font-weight:normal; text-align:left">{@link #offer(Object) offer(e)}</th>
- *    <td headers="Insert BDeque offer1">{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <th id="put" style="font-weight:normal; text-align:left">{@link #put(Object) put(e)}</th>
- *    <td headers="Insert BDeque put">{@link #putLast(Object) putLast(e)}</td>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <th id="offer2" style="font-weight:normal; text-align:left">{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</th>
- *    <td headers="Insert BDeque offer2">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *    <td>{@link #put(Object) put(e)}</td>
+ *    <td>{@link #putLast(Object) putLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <th id="Remove" rowspan="4" style="text-align:left; vertical-align:top">Remove</th>
- *    <th id="remove" style="font-weight:normal; text-align:left">{@link #remove() remove()}</th>
- *    <td headers="Remove BDeque remove">{@link #removeFirst() removeFirst()}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th id="poll1" style="font-weight:normal; text-align:left">{@link #poll() poll()}</th>
- *    <td headers="Remove BDeque poll1">{@link #pollFirst() pollFirst()}</td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
  *  </tr>
  *  <tr>
- *    <th id="take" style="font-weight:normal; text-align:left">{@link #take() take()}</th>
- *    <td headers="Remove BDeque take">{@link #takeFirst() takeFirst()}</td>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
  *  </tr>
  *  <tr>
- *    <th id="poll2" style="font-weight:normal; text-align:left">{@link #poll(long, TimeUnit) poll(time, unit)}</th>
- *    <td headers="Remove BDeque poll2">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *    <td>{@link #poll() poll()}</td>
+ *    <td>{@link #pollFirst() pollFirst()}</td>
  *  </tr>
  *  <tr>
- *    <th id="Examine" rowspan="2" style="text-align:left; vertical-align:top">Examine</th>
- *    <th id="element" style="font-weight:normal; text-align:left">{@link #element() element()}</th>
- *    <td headers="Examine BDeque element">{@link #getFirst() getFirst()}</td>
+ *    <td>{@link #take() take()}</td>
+ *    <td>{@link #takeFirst() takeFirst()}</td>
  *  </tr>
  *  <tr>
- *    <th id="peek" style="font-weight:normal; text-align:left">{@link #peek() peek()}</th>
- *    <td headers="Examine BDeque peek">{@link #peekFirst() peekFirst()}</td>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #peek() peek()}</td>
+ *    <td>{@link #peekFirst() peekFirst()}</td>
  *  </tr>
  * </table>
  *
@@ -188,7 +197,7 @@
  * the {@code BlockingDeque} in another thread.
  *
  * <p>This interface is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @since 1.6
@@ -399,9 +408,9 @@
      * @return {@code true} if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeFirstOccurrence(Object o);
 
@@ -417,9 +426,9 @@
      * @return {@code true} if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeLastOccurrence(Object o);
 
@@ -507,7 +516,7 @@
     /**
      * Retrieves and removes the head of the queue represented by this deque
      * (in other words, the first element of this deque).
-     * This method differs from {@link #poll() poll()} only in that it
+     * This method differs from {@link #poll poll} only in that it
      * throws an exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -558,7 +567,7 @@
     /**
      * Retrieves, but does not remove, the head of the queue represented by
      * this deque (in other words, the first element of this deque).
-     * This method differs from {@link #peek() peek} only in that it throws an
+     * This method differs from {@link #peek peek} only in that it throws an
      * exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -594,9 +603,9 @@
      * @return {@code true} if this deque changed as a result of the call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -609,9 +618,9 @@
      * @return {@code true} if this deque contains the specified element
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean contains(Object o);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
index 6fecc27..6f01b77 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -38,10 +38,16 @@
 import java.util.Collection;
 import java.util.Queue;
 
+// BEGIN android-note
+// removed link to collections framework docs from header
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
 /**
- * A {@link Queue} that additionally supports operations that wait for
- * the queue to become non-empty when retrieving an element, and wait
- * for space to become available in the queue when storing an element.
+ * A {@link java.util.Queue} that additionally supports operations
+ * that wait for the queue to become non-empty when retrieving an
+ * element, and wait for space to become available in the queue when
+ * storing an element.
  *
  * <p>{@code BlockingQueue} methods come in four forms, with different ways
  * of handling operations that cannot be satisfied immediately, but may be
@@ -52,35 +58,35 @@
  * and the fourth blocks for only a given maximum time limit before giving
  * up.  These methods are summarized in the following table:
  *
- * <table class="plain">
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
  * <caption>Summary of BlockingQueue methods</caption>
  *  <tr>
  *    <td></td>
- *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
- *    <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
- *    <th scope="col" style="font-weight:normal; font-style:italic">Blocks</th>
- *    <th scope="col" style="font-weight:normal; font-style:italic">Times out</th>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left">Insert</th>
- *    <td>{@link #add(Object) add(e)}</td>
- *    <td>{@link #offer(Object) offer(e)}</td>
- *    <td>{@link #put(Object) put(e)}</td>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #add add(e)}</td>
+ *    <td>{@link #offer offer(e)}</td>
+ *    <td>{@link #put put(e)}</td>
  *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left">Remove</th>
- *    <td>{@link #remove() remove()}</td>
- *    <td>{@link #poll() poll()}</td>
- *    <td>{@link #take() take()}</td>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #remove remove()}</td>
+ *    <td>{@link #poll poll()}</td>
+ *    <td>{@link #take take()}</td>
  *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left">Examine</th>
- *    <td>{@link #element() element()}</td>
- *    <td>{@link #peek() peek()}</td>
- *    <td style="font-style: italic">not applicable</td>
- *    <td style="font-style: italic">not applicable</td>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #element element()}</td>
+ *    <td>{@link #peek peek()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
  *  </tr>
  * </table>
  *
@@ -98,7 +104,7 @@
  *
  * <p>{@code BlockingQueue} implementations are designed to be used
  * primarily for producer-consumer queues, but additionally support
- * the {@link Collection} interface.  So, for example, it is
+ * the {@link java.util.Collection} interface.  So, for example, it is
  * possible to remove an arbitrary element from a queue using
  * {@code remove(x)}. However, such operations are in general
  * <em>not</em> performed very efficiently, and are intended for only
@@ -168,10 +174,7 @@
  * actions subsequent to the access or removal of that element from
  * the {@code BlockingQueue} in another thread.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
+ * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
  */
@@ -301,9 +304,9 @@
      * @return {@code true} if this queue changed as a result of the call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this queue
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -316,9 +319,9 @@
      * @return {@code true} if this queue contains the specified element
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this queue
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean contains(Object o);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
index 936ffc3..e98e1be 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
@@ -112,9 +110,9 @@
  * in a {@link NullPointerException} being thrown.
  *
  * @author Doug Lea
+ * @since 1.8
  * @param <T> The result type returned by this future's {@code join}
  * and {@code get} methods
- * @since 1.8
  */
 public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
 
@@ -127,29 +125,26 @@
      * applies across normal vs exceptional outcomes, sync vs async
      * actions, binary triggers, and various forms of completions.
      *
-     * Non-nullness of volatile field "result" indicates done.  It may
-     * be set directly if known to be thread-confined, else via CAS.
-     * An AltResult is used to box null as a result, as well as to
-     * hold exceptions.  Using a single field makes completion simple
-     * to detect and trigger.  Result encoding and decoding is
-     * straightforward but tedious and adds to the sprawl of trapping
-     * and associating exceptions with targets.  Minor simplifications
-     * rely on (static) NIL (to box null results) being the only
-     * AltResult with a null exception field, so we don't usually need
-     * explicit comparisons.  Even though some of the generics casts
-     * are unchecked (see SuppressWarnings annotations), they are
-     * placed to be appropriate even if checked.
+     * Non-nullness of field result (set via CAS) indicates done.  An
+     * AltResult is used to box null as a result, as well as to hold
+     * exceptions.  Using a single field makes completion simple to
+     * detect and trigger.  Encoding and decoding is straightforward
+     * but adds to the sprawl of trapping and associating exceptions
+     * with targets.  Minor simplifications rely on (static) NIL (to
+     * box null results) being the only AltResult with a null
+     * exception field, so we don't usually need explicit comparisons.
+     * Even though some of the generics casts are unchecked (see
+     * SuppressWarnings annotations), they are placed to be
+     * appropriate even if checked.
      *
      * Dependent actions are represented by Completion objects linked
      * as Treiber stacks headed by field "stack". There are Completion
-     * classes for each kind of action, grouped into:
-     * - single-input (UniCompletion),
-     * - two-input (BiCompletion),
-     * - projected (BiCompletions using exactly one of two inputs),
-     * - shared (CoCompletion, used by the second of two sources),
-     * - zero-input source actions,
-     * - Signallers that unblock waiters.
-     * Class Completion extends ForkJoinTask to enable async execution
+     * classes for each kind of action, grouped into single-input
+     * (UniCompletion), two-input (BiCompletion), projected
+     * (BiCompletions using either (not both) of two inputs), shared
+     * (CoCompletion, used by the second of two sources), zero-input
+     * source actions, and Signallers that unblock waiters. Class
+     * Completion extends ForkJoinTask to enable async execution
      * (adding no space overhead because we exploit its "tag" methods
      * to maintain claims). It is also declared as Runnable to allow
      * usage with arbitrary executors.
@@ -165,7 +160,7 @@
      *   encounter layers of adapters in common usages.
      *
      * * Boolean CompletableFuture method x(...) (for example
-     *   biApply) takes all of the arguments needed to check that an
+     *   uniApply) takes all of the arguments needed to check that an
      *   action is triggerable, and then either runs the action or
      *   arranges its async execution by executing its Completion
      *   argument, if present. The method returns true if known to be
@@ -175,32 +170,24 @@
      *   method with its held arguments, and on success cleans up.
      *   The mode argument allows tryFire to be called twice (SYNC,
      *   then ASYNC); the first to screen and trap exceptions while
-     *   arranging to execute, and the second when called from a task.
-     *   (A few classes are not used async so take slightly different
-     *   forms.)  The claim() callback suppresses function invocation
-     *   if already claimed by another thread.
-     *
-     * * Some classes (for example UniApply) have separate handling
-     *   code for when known to be thread-confined ("now" methods) and
-     *   for when shared (in tryFire), for efficiency.
+     *   arranging to execute, and the second when called from a
+     *   task. (A few classes are not used async so take slightly
+     *   different forms.)  The claim() callback suppresses function
+     *   invocation if already claimed by another thread.
      *
      * * CompletableFuture method xStage(...) is called from a public
-     *   stage method of CompletableFuture f. It screens user
+     *   stage method of CompletableFuture x. It screens user
      *   arguments and invokes and/or creates the stage object.  If
-     *   not async and already triggerable, the action is run
-     *   immediately.  Otherwise a Completion c is created, and
-     *   submitted to the executor if triggerable, or pushed onto f's
-     *   stack if not.  Completion actions are started via c.tryFire.
-     *   We recheck after pushing to a source future's stack to cover
-     *   possible races if the source completes while pushing.
-     *   Classes with two inputs (for example BiApply) deal with races
-     *   across both while pushing actions.  The second completion is
-     *   a CoCompletion pointing to the first, shared so that at most
-     *   one performs the action.  The multiple-arity methods allOf
-     *   does this pairwise to form trees of completions.  Method
-     *   anyOf is handled differently from allOf because completion of
-     *   any source should trigger a cleanStack of other sources.
-     *   Each AnyOf completion can reach others via a shared array.
+     *   not async and x is already complete, the action is run
+     *   immediately.  Otherwise a Completion c is created, pushed to
+     *   x's stack (unless done), and started or triggered via
+     *   c.tryFire.  This also covers races possible if x completes
+     *   while pushing.  Classes with two inputs (for example BiApply)
+     *   deal with races across both while pushing actions.  The
+     *   second completion is a CoCompletion pointing to the first,
+     *   shared so that at most one performs the action.  The
+     *   multiple-arity methods allOf and anyOf do this pairwise to
+     *   form trees of completions.
      *
      * Note that the generic type parameters of methods vary according
      * to whether "this" is a source, dependent, or completion.
@@ -225,30 +212,29 @@
      * pointing back to its sources. So we null out fields as soon as
      * possible.  The screening checks needed anyway harmlessly ignore
      * null arguments that may have been obtained during races with
-     * threads nulling out fields.  We also try to unlink non-isLive
-     * (fired or cancelled) Completions from stacks that might
-     * otherwise never be popped: Method cleanStack always unlinks non
-     * isLive completions from the head of stack; others may
-     * occasionally remain if racing with other cancellations or
-     * removals.
-     *
-     * Completion fields need not be declared as final or volatile
-     * because they are only visible to other threads upon safe
-     * publication.
+     * threads nulling out fields.  We also try to unlink fired
+     * Completions from stacks that might never be popped (see method
+     * postFire).  Completion fields need not be declared as final or
+     * volatile because they are only visible to other threads upon
+     * safe publication.
      */
 
     volatile Object result;       // Either the result or boxed AltResult
     volatile Completion stack;    // Top of Treiber stack of dependent actions
 
     final boolean internalComplete(Object r) { // CAS from null to r
-        return RESULT.compareAndSet(this, null, r);
+        return U.compareAndSwapObject(this, RESULT, null, r);
+    }
+
+    final boolean casStack(Completion cmp, Completion val) {
+        return U.compareAndSwapObject(this, STACK, cmp, val);
     }
 
     /** Returns true if successfully pushed c onto stack. */
     final boolean tryPushStack(Completion c) {
         Completion h = stack;
-        NEXT.set(c, h);         // CAS piggyback
-        return STACK.compareAndSet(this, h, c);
+        lazySetNext(c, h);
+        return U.compareAndSwapObject(this, STACK, h, c);
     }
 
     /** Unconditionally pushes c onto stack, retrying if necessary. */
@@ -268,7 +254,8 @@
 
     /** Completes with the null value, unless already completed. */
     final boolean completeNull() {
-        return RESULT.compareAndSet(this, null, NIL);
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      NIL);
     }
 
     /** Returns the encoding of the given non-exceptional value. */
@@ -278,7 +265,8 @@
 
     /** Completes with a non-exceptional result, unless already completed. */
     final boolean completeValue(T t) {
-        return RESULT.compareAndSet(this, null, (t == null) ? NIL : t);
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      (t == null) ? NIL : t);
     }
 
     /**
@@ -292,7 +280,8 @@
 
     /** Completes with an exceptional result, unless already completed. */
     final boolean completeThrowable(Throwable x) {
-        return RESULT.compareAndSet(this, null, encodeThrowable(x));
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x));
     }
 
     /**
@@ -319,7 +308,8 @@
      * existing CompletionException.
      */
     final boolean completeThrowable(Throwable x, Object r) {
-        return RESULT.compareAndSet(this, null, encodeThrowable(x, r));
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x, r));
     }
 
     /**
@@ -337,11 +327,10 @@
      */
     static Object encodeRelay(Object r) {
         Throwable x;
-        if (r instanceof AltResult
-            && (x = ((AltResult)r).ex) != null
-            && !(x instanceof CompletionException))
-            r = new AltResult(new CompletionException(x));
-        return r;
+        return (((r instanceof AltResult) &&
+                 (x = ((AltResult)r).ex) != null &&
+                 !(x instanceof CompletionException)) ?
+                new AltResult(new CompletionException(x)) : r);
     }
 
     /**
@@ -349,13 +338,14 @@
      * If exceptional, r is first coerced to a CompletionException.
      */
     final boolean completeRelay(Object r) {
-        return RESULT.compareAndSet(this, null, encodeRelay(r));
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeRelay(r));
     }
 
     /**
      * Reports result using Future.get conventions.
      */
-    private static Object reportGet(Object r)
+    private static <T> T reportGet(Object r)
         throws InterruptedException, ExecutionException {
         if (r == null) // by convention below, null means interrupted
             throw new InterruptedException();
@@ -370,13 +360,14 @@
                 x = cause;
             throw new ExecutionException(x);
         }
-        return r;
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
     }
 
     /**
      * Decodes outcome to return result or throw unchecked exception.
      */
-    private static Object reportJoin(Object r) {
+    private static <T> T reportJoin(Object r) {
         if (r instanceof AltResult) {
             Throwable x;
             if ((x = ((AltResult)r).ex) == null)
@@ -387,7 +378,8 @@
                 throw (CompletionException)x;
             throw new CompletionException(x);
         }
-        return r;
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
     }
 
     /* ------------- Async task preliminaries -------------- */
@@ -433,6 +425,12 @@
     static final int ASYNC  =  1;
     static final int NESTED = -1;
 
+    /**
+     * Spins before blocking in waitingGet
+     */
+    static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
+                              1 << 8 : 0);
+
     /* ------------- Base Completion classes and operations -------------- */
 
     @SuppressWarnings("serial")
@@ -457,6 +455,10 @@
         public final void setRawResult(Void v) {}
     }
 
+    static void lazySetNext(Completion c, Completion next) {
+        U.putOrderedObject(c, NEXT, next);
+    }
+
     /**
      * Pops and tries to trigger all reachable dependents.  Call only
      * when known to be done.
@@ -471,47 +473,40 @@
         while ((h = f.stack) != null ||
                (f != this && (h = (f = this).stack) != null)) {
             CompletableFuture<?> d; Completion t;
-            if (STACK.compareAndSet(f, h, t = h.next)) {
+            if (f.casStack(h, t = h.next)) {
                 if (t != null) {
                     if (f != this) {
                         pushStack(h);
                         continue;
                     }
-                    NEXT.compareAndSet(h, t, null); // try to detach
+                    h.next = null;    // detach
                 }
                 f = (d = h.tryFire(NESTED)) == null ? this : d;
             }
         }
     }
 
-    /** Traverses stack and unlinks one or more dead Completions, if found. */
+    /** Traverses stack and unlinks dead Completions. */
     final void cleanStack() {
-        Completion p = stack;
-        // ensure head of stack live
-        for (boolean unlinked = false;;) {
-            if (p == null)
-                return;
-            else if (p.isLive()) {
-                if (unlinked)
-                    return;
-                else
-                    break;
-            }
-            else if (STACK.weakCompareAndSet(this, p, (p = p.next)))
-                unlinked = true;
-            else
-                p = stack;
-        }
-        // try to unlink first non-live
-        for (Completion q = p.next; q != null;) {
+        for (Completion p = null, q = stack; q != null;) {
             Completion s = q.next;
             if (q.isLive()) {
                 p = q;
                 q = s;
-            } else if (NEXT.weakCompareAndSet(p, q, s))
-                break;
-            else
-                q = p.next;
+            }
+            else if (p == null) {
+                casStack(q, s);
+                q = stack;
+            }
+            else {
+                p.next = s;
+                if (p.isLive())
+                    q = s;
+                else {
+                    p = null;  // restart
+                    q = stack;
+                }
+            }
         }
     }
 
@@ -549,34 +544,24 @@
         final boolean isLive() { return dep != null; }
     }
 
-    /**
-     * Pushes the given completion unless it completes while trying.
-     * Caller should first check that result is null.
-     */
-    final void unipush(Completion c) {
+    /** Pushes the given completion (if it exists) unless done. */
+    final void push(UniCompletion<?,?> c) {
         if (c != null) {
-            while (!tryPushStack(c)) {
-                if (result != null) {
-                    NEXT.set(c, null);
-                    break;
-                }
-            }
-            if (result != null)
-                c.tryFire(SYNC);
+            while (result == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
         }
     }
 
     /**
-     * Post-processing by dependent after successful UniCompletion tryFire.
-     * Tries to clean stack of source a, and then either runs postComplete
-     * or returns this to caller, depending on mode.
+     * Post-processing by dependent after successful UniCompletion
+     * tryFire.  Tries to clean stack of source a, and then either runs
+     * postComplete or returns this to caller, depending on mode.
      */
     final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
         if (a != null && a.stack != null) {
-            Object r;
-            if ((r = a.result) == null)
+            if (mode < 0 || a.result == null)
                 a.cleanStack();
-            if (mode >= 0 && (r != null || a.result != null))
+            else
                 a.postComplete();
         }
         if (result != null && stack != null) {
@@ -598,65 +583,48 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            Object r; Throwable x; Function<? super T,? extends V> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null)
+            if ((d = dep) == null ||
+                !d.uniApply(a = src, fn, mode > 0 ? null : this))
                 return null;
-            tryComplete: if (d.result == null) {
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        d.completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    else {
-                        @SuppressWarnings("unchecked") T t = (T) r;
-                        d.completeValue(f.apply(t));
-                    }
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
+    final <S> boolean uniApply(CompletableFuture<S> a,
+                               Function<? super S,? extends T> f,
+                               UniApply<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                completeValue(f.apply(s));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private <V> CompletableFuture<V> uniApplyStage(
         Executor e, Function<? super T,? extends V> f) {
         if (f == null) throw new NullPointerException();
-        Object r;
-        if ((r = result) != null)
-            return uniApplyNow(r, e, f);
         CompletableFuture<V> d = newIncompleteFuture();
-        unipush(new UniApply<T,V>(e, d, this, f));
-        return d;
-    }
-
-    private <V> CompletableFuture<V> uniApplyNow(
-        Object r, Executor e, Function<? super T,? extends V> f) {
-        Throwable x;
-        CompletableFuture<V> d = newIncompleteFuture();
-        if (r instanceof AltResult) {
-            if ((x = ((AltResult)r).ex) != null) {
-                d.result = encodeThrowable(x, r);
-                return d;
-            }
-            r = null;
-        }
-        try {
-            if (e != null) {
-                e.execute(new UniApply<T,V>(null, d, this, f));
-            } else {
-                @SuppressWarnings("unchecked") T t = (T) r;
-                d.result = d.encodeValue(f.apply(t));
-            }
-        } catch (Throwable ex) {
-            d.result = encodeThrowable(ex);
+        if (e != null || !d.uniApply(this, f, null)) {
+            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
         }
         return d;
     }
@@ -670,67 +638,48 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            Object r; Throwable x; Consumer<? super T> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null)
+            if ((d = dep) == null ||
+                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
                 return null;
-            tryComplete: if (d.result == null) {
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        d.completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    else {
-                        @SuppressWarnings("unchecked") T t = (T) r;
-                        f.accept(t);
-                        d.completeNull();
-                    }
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
+    final <S> boolean uniAccept(CompletableFuture<S> a,
+                                Consumer<? super S> f, UniAccept<S> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                f.accept(s);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private CompletableFuture<Void> uniAcceptStage(Executor e,
                                                    Consumer<? super T> f) {
         if (f == null) throw new NullPointerException();
-        Object r;
-        if ((r = result) != null)
-            return uniAcceptNow(r, e, f);
         CompletableFuture<Void> d = newIncompleteFuture();
-        unipush(new UniAccept<T>(e, d, this, f));
-        return d;
-    }
-
-    private CompletableFuture<Void> uniAcceptNow(
-        Object r, Executor e, Consumer<? super T> f) {
-        Throwable x;
-        CompletableFuture<Void> d = newIncompleteFuture();
-        if (r instanceof AltResult) {
-            if ((x = ((AltResult)r).ex) != null) {
-                d.result = encodeThrowable(x, r);
-                return d;
-            }
-            r = null;
-        }
-        try {
-            if (e != null) {
-                e.execute(new UniAccept<T>(null, d, this, f));
-            } else {
-                @SuppressWarnings("unchecked") T t = (T) r;
-                f.accept(t);
-                d.result = NIL;
-            }
-        } catch (Throwable ex) {
-            d.result = encodeThrowable(ex);
+        if (e != null || !d.uniAccept(this, f, null)) {
+            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
         }
         return d;
     }
@@ -744,56 +693,42 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            Object r; Throwable x; Runnable f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null)
+            if ((d = dep) == null ||
+                !d.uniRun(a = src, fn, mode > 0 ? null : this))
                 return null;
-            if (d.result == null) {
-                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                    d.completeThrowable(x, r);
-                else
-                    try {
-                        if (mode <= 0 && !claim())
-                            return null;
-                        else {
-                            f.run();
-                            d.completeNull();
-                        }
-                    } catch (Throwable ex) {
-                        d.completeThrowable(ex);
-                    }
-            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
-        if (f == null) throw new NullPointerException();
-        Object r;
-        if ((r = result) != null)
-            return uniRunNow(r, e, f);
-        CompletableFuture<Void> d = newIncompleteFuture();
-        unipush(new UniRun<T>(e, d, this, f));
-        return d;
+    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
     }
 
-    private CompletableFuture<Void> uniRunNow(Object r, Executor e, Runnable f) {
-        Throwable x;
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-            d.result = encodeThrowable(x, r);
-        else
-            try {
-                if (e != null) {
-                    e.execute(new UniRun<T>(null, d, this, f));
-                } else {
-                    f.run();
-                    d.result = NIL;
-                }
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.uniRun(this, f, null)) {
+            UniRun<T> c = new UniRun<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -807,20 +742,20 @@
         }
         final CompletableFuture<T> tryFire(int mode) {
             CompletableFuture<T> d; CompletableFuture<T> a;
-            Object r; BiConsumer<? super T, ? super Throwable> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || !d.uniWhenComplete(r, f, mode > 0 ? null : this))
+            if ((d = dep) == null ||
+                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniWhenComplete(Object r,
+    final boolean uniWhenComplete(CompletableFuture<T> a,
                                   BiConsumer<? super T,? super Throwable> f,
                                   UniWhenComplete<T> c) {
-        T t; Throwable x = null;
+        Object r; T t; Throwable x = null;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -852,17 +787,10 @@
         Executor e, BiConsumer<? super T, ? super Throwable> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        Object r;
-        if ((r = result) == null)
-            unipush(new UniWhenComplete<T>(e, d, this, f));
-        else if (e == null)
-            d.uniWhenComplete(r, f, null);
-        else {
-            try {
-                e.execute(new UniWhenComplete<T>(null, d, this, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.uniWhenComplete(this, f, null)) {
+            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
         }
         return d;
     }
@@ -877,20 +805,20 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            Object r; BiFunction<? super T, Throwable, ? extends V> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || !d.uniHandle(r, f, mode > 0 ? null : this))
+            if ((d = dep) == null ||
+                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniHandle(Object r,
+    final <S> boolean uniHandle(CompletableFuture<S> a,
                                 BiFunction<? super S, Throwable, ? extends T> f,
                                 UniHandle<S,T> c) {
-        S s; Throwable x;
+        Object r; S s; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -915,17 +843,10 @@
         Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        Object r;
-        if ((r = result) == null)
-            unipush(new UniHandle<T,V>(e, d, this, f));
-        else if (e == null)
-            d.uniHandle(r, f, null);
-        else {
-            try {
-                e.execute(new UniHandle<T,V>(null, d, this, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.uniHandle(this, f, null)) {
+            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
         }
         return d;
     }
@@ -940,20 +861,19 @@
         final CompletableFuture<T> tryFire(int mode) { // never ASYNC
             // assert mode != ASYNC;
             CompletableFuture<T> d; CompletableFuture<T> a;
-            Object r; Function<? super Throwable, ? extends T> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || !d.uniExceptionally(r, f, this))
+            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniExceptionally(Object r,
+    final boolean uniExceptionally(CompletableFuture<T> a,
                                    Function<? super Throwable, ? extends T> f,
                                    UniExceptionally<T> c) {
-        Throwable x;
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
         if (result == null) {
             try {
                 if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
@@ -973,39 +893,47 @@
         Function<Throwable, ? extends T> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        Object r;
-        if ((r = result) == null)
-            unipush(new UniExceptionally<T>(d, this, f));
-        else
-            d.uniExceptionally(r, f, null);
+        if (!d.uniExceptionally(this, f, null)) {
+            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
     @SuppressWarnings("serial")
-    static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
-        UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
+    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
             super(null, dep, src);
         }
-        final CompletableFuture<U> tryFire(int mode) {
-            CompletableFuture<U> d; CompletableFuture<T> a; Object r;
-            if ((d = dep) == null
-                || (a = src) == null || (r = a.result) == null)
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniRelay(a = src))
                 return null;
-            if (d.result == null)
-                d.completeRelay(r);
             src = null; dep = null;
             return d.postFire(a, mode);
         }
     }
 
-    private static <U, T extends U> CompletableFuture<U> uniCopyStage(
-        CompletableFuture<T> src) {
+    final boolean uniRelay(CompletableFuture<T> a) {
         Object r;
-        CompletableFuture<U> d = src.newIncompleteFuture();
-        if ((r = src.result) != null)
-            d.result = encodeRelay(r);
-        else
-            src.unipush(new UniRelay<U,T>(d, src));
+        if (a == null || (r = a.result) == null)
+            return false;
+        if (result == null) // no need to claim
+            completeRelay(r);
+        return true;
+    }
+
+    private CompletableFuture<T> uniCopyStage() {
+        Object r;
+        CompletableFuture<T> d = newIncompleteFuture();
+        if ((r = result) != null)
+            d.completeRelay(r);
+        else {
+            UniRelay<T> c = new UniRelay<T>(d, this);
+            push(c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -1014,7 +942,9 @@
         if ((r = result) != null)
             return new MinimalStage<T>(encodeRelay(r));
         MinimalStage<T> d = new MinimalStage<T>();
-        unipush(new UniRelay<T,T>(d, this));
+        UniRelay<T> c = new UniRelay<T>(d, this);
+        push(c);
+        c.tryFire(SYNC);
         return d;
     }
 
@@ -1028,48 +958,54 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            Function<? super T, ? extends CompletionStage<V>> f;
-            Object r; Throwable x;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null)
+            if ((d = dep) == null ||
+                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
                 return null;
-            tryComplete: if (d.result == null) {
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        d.completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    @SuppressWarnings("unchecked") T t = (T) r;
-                    CompletableFuture<V> g = f.apply(t).toCompletableFuture();
-                    if ((r = g.result) != null)
-                        d.completeRelay(r);
-                    else {
-                        g.unipush(new UniRelay<V,V>(d, g));
-                        if (d.result == null)
-                            return null;
-                    }
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
+    final <S> boolean uniCompose(
+        CompletableFuture<S> a,
+        Function<? super S, ? extends CompletionStage<T>> f,
+        UniCompose<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+                if (g.result == null || !uniRelay(g)) {
+                    UniRelay<T> copy = new UniRelay<T>(this, g);
+                    g.push(copy);
+                    copy.tryFire(SYNC);
+                    if (result == null)
+                        return false;
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private <V> CompletableFuture<V> uniComposeStage(
         Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
         if (f == null) throw new NullPointerException();
-        CompletableFuture<V> d = newIncompleteFuture();
         Object r, s; Throwable x;
-        if ((r = result) == null)
-            unipush(new UniCompose<T,V>(e, d, this, f));
-        else if (e == null) {
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e == null && (r = result) != null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
                     d.result = encodeThrowable(x, r);
@@ -1081,20 +1017,21 @@
                 @SuppressWarnings("unchecked") T t = (T) r;
                 CompletableFuture<V> g = f.apply(t).toCompletableFuture();
                 if ((s = g.result) != null)
-                    d.result = encodeRelay(s);
+                    d.completeRelay(s);
                 else {
-                    g.unipush(new UniRelay<V,V>(d, g));
+                    UniRelay<V> c = new UniRelay<V>(d, g);
+                    g.push(c);
+                    c.tryFire(SYNC);
                 }
+                return d;
             } catch (Throwable ex) {
                 d.result = encodeThrowable(ex);
+                return d;
             }
         }
-        else
-            try {
-                e.execute(new UniCompose<T,V>(null, d, this, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+        push(c);
+        c.tryFire(SYNC);
         return d;
     }
 
@@ -1124,28 +1061,21 @@
         }
         final boolean isLive() {
             BiCompletion<?,?,?> c;
-            return (c = base) != null
-                // && c.isLive()
-                && c.dep != null;
+            return (c = base) != null && c.dep != null;
         }
     }
 
-    /**
-     * Pushes completion to this and b unless both done.
-     * Caller should first check that either result or b.result is null.
-     */
+    /** Pushes completion to this and b unless both done. */
     final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            while (result == null) {
-                if (tryPushStack(c)) {
-                    if (b.result == null)
-                        b.unipush(new CoCompletion(c));
-                    else if (result != null)
-                        c.tryFire(SYNC);
-                    return;
-                }
+            Object r;
+            while ((r = result) == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+            if (b != null && b != this && b.result == null) {
+                Completion q = (r != null) ? c : new CoCompletion(c);
+                while (b.result == null && !b.tryPushStack(q))
+                    lazySetNext(q, null); // clear on failure
             }
-            b.unipush(c);
         }
     }
 
@@ -1153,10 +1083,9 @@
     final CompletableFuture<T> postFire(CompletableFuture<?> a,
                                         CompletableFuture<?> b, int mode) {
         if (b != null && b.stack != null) { // clean second source
-            Object r;
-            if ((r = b.result) == null)
+            if (mode < 0 || b.result == null)
                 b.cleanStack();
-            if (mode >= 0 && (r != null || b.result != null))
+            else
                 b.postComplete();
         }
         return postFire(a, mode);
@@ -1174,21 +1103,22 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r, s; BiFunction<? super T,? super U,? extends V> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || (b = snd) == null || (s = b.result) == null
-                || !d.biApply(r, s, f, mode > 0 ? null : this))
+            if ((d = dep) == null ||
+                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biApply(Object r, Object s,
+    final <R,S> boolean biApply(CompletableFuture<R> a,
+                                CompletableFuture<S> b,
                                 BiFunction<? super R,? super S,? extends T> f,
                                 BiApply<R,S,T> c) {
-        Throwable x;
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1220,20 +1150,15 @@
     private <U,V> CompletableFuture<V> biApplyStage(
         Executor e, CompletionStage<U> o,
         BiFunction<? super T,? super U,? extends V> f) {
-        CompletableFuture<U> b; Object r, s;
+        CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        if ((r = result) == null || (s = b.result) == null)
-            bipush(b, new BiApply<T,U,V>(e, d, this, b, f));
-        else if (e == null)
-            d.biApply(r, s, f, null);
-        else
-            try {
-                e.execute(new BiApply<T,U,V>(null, d, this, b, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.biApply(this, b, f, null)) {
+            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -1249,21 +1174,22 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r, s; BiConsumer<? super T,? super U> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || (b = snd) == null || (s = b.result) == null
-                || !d.biAccept(r, s, f, mode > 0 ? null : this))
+            if ((d = dep) == null ||
+                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biAccept(Object r, Object s,
+    final <R,S> boolean biAccept(CompletableFuture<R> a,
+                                 CompletableFuture<S> b,
                                  BiConsumer<? super R,? super S> f,
                                  BiAccept<R,S> c) {
-        Throwable x;
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1296,20 +1222,15 @@
     private <U> CompletableFuture<Void> biAcceptStage(
         Executor e, CompletionStage<U> o,
         BiConsumer<? super T,? super U> f) {
-        CompletableFuture<U> b; Object r, s;
+        CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if ((r = result) == null || (s = b.result) == null)
-            bipush(b, new BiAccept<T,U>(e, d, this, b, f));
-        else if (e == null)
-            d.biAccept(r, s, f, null);
-        else
-            try {
-                e.execute(new BiAccept<T,U>(null, d, this, b, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.biAccept(this, b, f, null)) {
+            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -1317,7 +1238,8 @@
     static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         BiRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src, CompletableFuture<U> snd,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1325,25 +1247,25 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r, s; Runnable f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (r = a.result) == null
-                || (b = snd) == null || (s = b.result) == null
-                || !d.biRun(r, s, f, mode > 0 ? null : this))
+            if ((d = dep) == null ||
+                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final boolean biRun(Object r, Object s, Runnable f, BiRun<?,?> c) {
-        Throwable x; Object z;
+    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, BiRun<?,?> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
         if (result == null) {
-            if ((r instanceof AltResult
-                 && (x = ((AltResult)(z = r)).ex) != null) ||
-                (s instanceof AltResult
-                 && (x = ((AltResult)(z = s)).ex) != null))
-                completeThrowable(x, z);
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
             else
                 try {
                     if (c != null && !c.claim())
@@ -1359,52 +1281,52 @@
 
     private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
-        CompletableFuture<?> b; Object r, s;
+        CompletableFuture<?> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if ((r = result) == null || (s = b.result) == null)
-            bipush(b, new BiRun<>(e, d, this, b, f));
-        else if (e == null)
-            d.biRun(r, s, f, null);
-        else
-            try {
-                e.execute(new BiRun<>(null, d, this, b, f));
-            } catch (Throwable ex) {
-                d.result = encodeThrowable(ex);
-            }
+        if (e != null || !d.biRun(this, b, f, null)) {
+            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
     @SuppressWarnings("serial")
     static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
         BiRelay(CompletableFuture<Void> dep,
-                CompletableFuture<T> src, CompletableFuture<U> snd) {
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
             super(null, dep, src, snd);
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r, s, z; Throwable x;
-            if ((d = dep) == null
-                || (a = src) == null || (r = a.result) == null
-                || (b = snd) == null || (s = b.result) == null)
+            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
                 return null;
-            if (d.result == null) {
-                if ((r instanceof AltResult
-                     && (x = ((AltResult)(z = r)).ex) != null) ||
-                    (s instanceof AltResult
-                     && (x = ((AltResult)(z = s)).ex) != null))
-                    d.completeThrowable(x, z);
-                else
-                    d.completeNull();
-            }
             src = null; snd = null; dep = null;
             return d.postFire(a, b, mode);
         }
     }
 
+    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                completeNull();
+        }
+        return true;
+    }
+
     /** Recursively constructs a tree of completions. */
     static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
                                            int lo, int hi) {
@@ -1412,44 +1334,39 @@
         if (lo > hi) // empty
             d.result = NIL;
         else {
-            CompletableFuture<?> a, b; Object r, s, z; Throwable x;
+            CompletableFuture<?> a, b;
             int mid = (lo + hi) >>> 1;
             if ((a = (lo == mid ? cfs[lo] :
                       andTree(cfs, lo, mid))) == null ||
                 (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
                       andTree(cfs, mid+1, hi))) == null)
                 throw new NullPointerException();
-            if ((r = a.result) == null || (s = b.result) == null)
-                a.bipush(b, new BiRelay<>(d, a, b));
-            else if ((r instanceof AltResult
-                      && (x = ((AltResult)(z = r)).ex) != null) ||
-                     (s instanceof AltResult
-                      && (x = ((AltResult)(z = s)).ex) != null))
-                d.result = encodeThrowable(x, z);
-            else
-                d.result = NIL;
+            if (!d.biRelay(a, b)) {
+                BiRelay<?,?> c = new BiRelay<>(d, a, b);
+                a.bipush(b, c);
+                c.tryFire(SYNC);
+            }
         }
         return d;
     }
 
     /* ------------- Projected (Ored) BiCompletions -------------- */
 
-    /**
-     * Pushes completion to this and b unless either done.
-     * Caller should first check that result and b.result are both null.
-     */
+    /** Pushes completion to this and b unless either done. */
     final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            while (!tryPushStack(c)) {
-                if (result != null) {
-                    NEXT.set(c, null);
+            while ((b == null || b.result == null) && result == null) {
+                if (tryPushStack(c)) {
+                    if (b != null && b != this && b.result == null) {
+                        Completion q = new CoCompletion(c);
+                        while (result == null && b.result == null &&
+                               !b.tryPushStack(q))
+                            lazySetNext(q, null); // clear on failure
+                    }
                     break;
                 }
+                lazySetNext(c, null); // clear on failure
             }
-            if (result != null)
-                c.tryFire(SYNC);
-            else
-                b.unipush(new CoCompletion(c));
         }
     }
 
@@ -1457,7 +1374,8 @@
     static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
         Function<? super T,? extends V> fn;
         OrApply(Executor executor, CompletableFuture<V> dep,
-                CompletableFuture<T> src, CompletableFuture<U> snd,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd,
                 Function<? super T,? extends V> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1465,46 +1383,54 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r; Throwable x; Function<? super T,? extends V> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (b = snd) == null
-                || ((r = a.result) == null && (r = b.result) == null))
+            if ((d = dep) == null ||
+                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
-            tryComplete: if (d.result == null) {
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    if (r instanceof AltResult) {
-                        if ((x = ((AltResult)r).ex) != null) {
-                            d.completeThrowable(x, r);
-                            break tryComplete;
-                        }
-                        r = null;
-                    }
-                    @SuppressWarnings("unchecked") T t = (T) r;
-                    d.completeValue(f.apply(t));
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
+    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+                                          CompletableFuture<S> b,
+                                          Function<? super R, ? extends T> f,
+                                          OrApply<R,S,T> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                completeValue(f.apply(rr));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private <U extends T,V> CompletableFuture<V> orApplyStage(
-        Executor e, CompletionStage<U> o, Function<? super T, ? extends V> f) {
+        Executor e, CompletionStage<U> o,
+        Function<? super T, ? extends V> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
-
-        Object r; CompletableFuture<? extends T> z;
-        if ((r = (z = this).result) != null ||
-            (r = (z = b).result) != null)
-            return z.uniApplyNow(r, e, f);
-
         CompletableFuture<V> d = newIncompleteFuture();
-        orpush(b, new OrApply<T,U,V>(e, d, this, b, f));
+        if (e != null || !d.orApply(this, b, f, null)) {
+            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -1512,7 +1438,8 @@
     static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
         Consumer<? super T> fn;
         OrAccept(Executor executor, CompletableFuture<Void> dep,
-                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 CompletableFuture<T> src,
+                 CompletableFuture<U> snd,
                  Consumer<? super T> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1520,47 +1447,54 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r; Throwable x; Consumer<? super T> f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (b = snd) == null
-                || ((r = a.result) == null && (r = b.result) == null))
+            if ((d = dep) == null ||
+                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
-            tryComplete: if (d.result == null) {
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    if (r instanceof AltResult) {
-                        if ((x = ((AltResult)r).ex) != null) {
-                            d.completeThrowable(x, r);
-                            break tryComplete;
-                        }
-                        r = null;
-                    }
-                    @SuppressWarnings("unchecked") T t = (T) r;
-                    f.accept(t);
-                    d.completeNull();
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
+    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+                                           CompletableFuture<S> b,
+                                           Consumer<? super R> f,
+                                           OrAccept<R,S> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                f.accept(rr);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private <U extends T> CompletableFuture<Void> orAcceptStage(
         Executor e, CompletionStage<U> o, Consumer<? super T> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
-
-        Object r; CompletableFuture<? extends T> z;
-        if ((r = (z = this).result) != null ||
-            (r = (z = b).result) != null)
-            return z.uniAcceptNow(r, e, f);
-
         CompletableFuture<Void> d = newIncompleteFuture();
-        orpush(b, new OrAccept<T,U>(e, d, this, b, f));
+        if (e != null || !d.orAccept(this, b, f, null)) {
+            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
@@ -1568,7 +1502,8 @@
     static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         OrRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src, CompletableFuture<U> snd,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1576,83 +1511,99 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            Object r; Throwable x; Runnable f;
-            if ((d = dep) == null || (f = fn) == null
-                || (a = src) == null || (b = snd) == null
-                || ((r = a.result) == null && (r = b.result) == null))
+            if ((d = dep) == null ||
+                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
                 return null;
-            if (d.result == null) {
-                try {
-                    if (mode <= 0 && !claim())
-                        return null;
-                    else if (r instanceof AltResult
-                        && (x = ((AltResult)r).ex) != null)
-                        d.completeThrowable(x, r);
-                    else {
-                        f.run();
-                        d.completeNull();
-                    }
-                } catch (Throwable ex) {
-                    d.completeThrowable(ex);
-                }
-            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
+    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, OrRun<?,?> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    completeThrowable(x, r);
+                else {
+                    f.run();
+                    completeNull();
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
     private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
         CompletableFuture<?> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
-
-        Object r; CompletableFuture<?> z;
-        if ((r = (z = this).result) != null ||
-            (r = (z = b).result) != null)
-            return z.uniRunNow(r, e, f);
-
         CompletableFuture<Void> d = newIncompleteFuture();
-        orpush(b, new OrRun<>(e, d, this, b, f));
+        if (e != null || !d.orRun(this, b, f, null)) {
+            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
         return d;
     }
 
-    /** Completion for an anyOf input future. */
     @SuppressWarnings("serial")
-    static class AnyOf extends Completion {
-        CompletableFuture<Object> dep; CompletableFuture<?> src;
-        CompletableFuture<?>[] srcs;
-        AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
-              CompletableFuture<?>[] srcs) {
-            this.dep = dep; this.src = src; this.srcs = srcs;
+    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
         }
         final CompletableFuture<Object> tryFire(int mode) {
-            // assert mode != ASYNC;
-            CompletableFuture<Object> d; CompletableFuture<?> a;
-            CompletableFuture<?>[] as;
-            Object r;
-            if ((d = dep) == null
-                || (a = src) == null || (r = a.result) == null
-                || (as = srcs) == null)
-                return null;
-            dep = null; src = null; srcs = null;
-            if (d.completeRelay(r)) {
-                for (CompletableFuture<?> b : as)
-                    if (b != a)
-                        b.cleanStack();
-                if (mode < 0)
-                    return d;
-                else
-                    d.postComplete();
-            }
-            return null;
-        }
-        final boolean isLive() {
             CompletableFuture<Object> d;
-            return (d = dep) != null && d.result == null;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
         }
     }
 
+    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null))
+            return false;
+        if (result == null)
+            completeRelay(r);
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+                                            int lo, int hi) {
+        CompletableFuture<Object> d = new CompletableFuture<Object>();
+        if (lo <= hi) {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      orTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      orTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if (!d.orRelay(a, b)) {
+                OrRelay<?,?> c = new OrRelay<>(d, a, b);
+                a.orpush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
     /* ------------- Zero-input Async forms -------------- */
 
     @SuppressWarnings("serial")
@@ -1665,7 +1616,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return false; }
+        public final boolean exec() { run(); return true; }
 
         public void run() {
             CompletableFuture<T> d; Supplier<? extends T> f;
@@ -1701,7 +1652,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return false; }
+        public final boolean exec() { run(); return true; }
 
         public void run() {
             CompletableFuture<Void> d; Runnable f;
@@ -1785,13 +1736,15 @@
     private Object waitingGet(boolean interruptible) {
         Signaller q = null;
         boolean queued = false;
+        int spins = SPINS;
         Object r;
         while ((r = result) == null) {
-            if (q == null) {
-                q = new Signaller(interruptible, 0L, 0L);
-                if (Thread.currentThread() instanceof ForkJoinWorkerThread)
-                    ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+            if (spins > 0) {
+                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
+                    --spins;
             }
+            else if (q == null)
+                q = new Signaller(interruptible, 0L, 0L);
             else if (!queued)
                 queued = tryPushStack(q);
             else {
@@ -1804,14 +1757,16 @@
                     break;
             }
         }
-        if (q != null && queued) {
+        if (q != null) {
             q.thread = null;
-            if (!interruptible && q.interrupted)
-                Thread.currentThread().interrupt();
-            if (r == null)
-                cleanStack();
+            if (q.interrupted) {
+                if (interruptible)
+                    cleanStack();
+                else
+                    Thread.currentThread().interrupt();
+            }
         }
-        if (r != null || (r = result) != null)
+        if (r != null)
             postComplete();
         return r;
     }
@@ -1829,12 +1784,9 @@
             Signaller q = null;
             boolean queued = false;
             Object r;
-            while ((r = result) == null) { // similar to untimed
-                if (q == null) {
+            while ((r = result) == null) { // similar to untimed, without spins
+                if (q == null)
                     q = new Signaller(true, nanos, deadline);
-                    if (Thread.currentThread() instanceof ForkJoinWorkerThread)
-                        ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
-                }
                 else if (!queued)
                     queued = tryPushStack(q);
                 else if (q.nanos <= 0L)
@@ -1849,13 +1801,12 @@
                         break;
                 }
             }
-            if (q != null && queued) {
+            if (q != null)
                 q.thread = null;
-                if (r == null)
-                    cleanStack();
-            }
-            if (r != null || (r = result) != null)
+            if (r != null)
                 postComplete();
+            else
+                cleanStack();
             if (r != null || (q != null && q.interrupted))
                 return r;
         }
@@ -1967,12 +1918,9 @@
      * @throws InterruptedException if the current thread was interrupted
      * while waiting
      */
-    @SuppressWarnings("unchecked")
     public T get() throws InterruptedException, ExecutionException {
         Object r;
-        if ((r = result) == null)
-            r = waitingGet(true);
-        return (T) reportGet(r);
+        return reportGet((r = result) == null ? waitingGet(true) : r);
     }
 
     /**
@@ -1988,14 +1936,11 @@
      * while waiting
      * @throws TimeoutException if the wait timed out
      */
-    @SuppressWarnings("unchecked")
     public T get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException {
-        long nanos = unit.toNanos(timeout);
         Object r;
-        if ((r = result) == null)
-            r = timedGet(nanos);
-        return (T) reportGet(r);
+        long nanos = unit.toNanos(timeout);
+        return reportGet((r = result) == null ? timedGet(nanos) : r);
     }
 
     /**
@@ -2012,12 +1957,9 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
-    @SuppressWarnings("unchecked")
     public T join() {
         Object r;
-        if ((r = result) == null)
-            r = waitingGet(false);
-        return (T) reportJoin(r);
+        return reportJoin((r = result) == null ? waitingGet(false) : r);
     }
 
     /**
@@ -2030,10 +1972,9 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
-    @SuppressWarnings("unchecked")
     public T getNow(T valueIfAbsent) {
         Object r;
-        return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
+        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
     }
 
     /**
@@ -2329,28 +2270,7 @@
      * {@code null}
      */
     public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
-        int n; Object r;
-        if ((n = cfs.length) <= 1)
-            return (n == 0)
-                ? new CompletableFuture<Object>()
-                : uniCopyStage(cfs[0]);
-        for (CompletableFuture<?> cf : cfs)
-            if ((r = cf.result) != null)
-                return new CompletableFuture<Object>(encodeRelay(r));
-        cfs = cfs.clone();
-        CompletableFuture<Object> d = new CompletableFuture<>();
-        for (CompletableFuture<?> cf : cfs)
-            cf.unipush(new AnyOf(d, cf, cfs));
-        // If d was completed while we were adding completions, we should
-        // clean the stack of any sources that may have had completions
-        // pushed on their stack after d was completed.
-        if (d.result != null)
-            for (int i = 0, len = cfs.length; i < len; i++)
-                if (cfs[i].result != null)
-                    for (i++; i < len; i++)
-                        if (cfs[i].result == null)
-                            cfs[i].cleanStack();
-        return d;
+        return orTree(cfs, 0, cfs.length - 1);
     }
 
     /* ------------- Control and status methods -------------- */
@@ -2466,13 +2386,13 @@
         for (Completion p = stack; p != null; p = p.next)
             ++count;
         return super.toString() +
-            ((r == null)
-             ? ((count == 0)
-                ? "[Not completed]"
-                : "[Not completed, " + count + " dependents]")
-             : (((r instanceof AltResult) && ((AltResult)r).ex != null)
-                ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
-                : "[Completed normally]"));
+            ((r == null) ?
+             ((count == 0) ?
+              "[Not completed]" :
+              "[Not completed, " + count + " dependents]") :
+             (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
+              "[Completed exceptionally]" :
+              "[Completed normally]"));
     }
 
     // jdk9 additions
@@ -2522,7 +2442,7 @@
      * @since 9
      */
     public CompletableFuture<T> copy() {
-        return uniCopyStage(this);
+        return uniCopyStage();
     }
 
     /**
@@ -2535,13 +2455,6 @@
      * exceptionally with a CompletionException with this exception as
      * cause.
      *
-     * <p>Unless overridden by a subclass, a new non-minimal
-     * CompletableFuture with all methods available can be obtained from
-     * a minimal CompletionStage via {@link #toCompletableFuture()}.
-     * For example, completion of a minimal stage can be awaited by
-     *
-     * <pre> {@code minimalStage.toCompletableFuture().join(); }</pre>
-     *
      * @return the new CompletionStage
      * @since 9
      */
@@ -2836,30 +2749,23 @@
         @Override public CompletableFuture<T> completeOnTimeout
             (T value, long timeout, TimeUnit unit) {
             throw new UnsupportedOperationException(); }
-        @Override public CompletableFuture<T> toCompletableFuture() {
-            Object r;
-            if ((r = result) != null)
-                return new CompletableFuture<T>(encodeRelay(r));
-            else {
-                CompletableFuture<T> d = new CompletableFuture<>();
-                unipush(new UniRelay<T,T>(d, this));
-                return d;
-            }
-        }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle RESULT;
-    private static final VarHandle STACK;
-    private static final VarHandle NEXT;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long RESULT;
+    private static final long STACK;
+    private static final long NEXT;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class);
-            STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
-            NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
+            RESULT = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("result"));
+            STACK = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("stack"));
+            NEXT = U.objectFieldOffset
+                (Completion.class.getDeclaredField("next"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionService.java b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
index 5e5232e..f647e21 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
@@ -57,8 +57,6 @@
  * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
  * actions taken by that task, which in turn <i>happen-before</i>
  * actions following a successful return from the corresponding {@code take()}.
- *
- * @since 1.5
  */
 public interface CompletionService<V> {
     /**
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
index 70b601a..d855945 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
@@ -856,9 +856,13 @@
      * CompletableFuture, this method may return this stage itself.
      * Otherwise, invocation of this method may be equivalent in
      * effect to {@code thenApply(x -> x)}, but returning an instance
-     * of type {@code CompletableFuture}.
+     * of type {@code CompletableFuture}. A CompletionStage
+     * implementation that does not choose to interoperate with others
+     * may throw {@code UnsupportedOperationException}.
      *
      * @return the CompletableFuture
+     * @throws UnsupportedOperationException if this implementation
+     * does not interoperate with CompletableFuture
      */
     public CompletableFuture<T> toCompletableFuture();
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index 2cf8c86..5407963 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -68,7 +68,10 @@
 import java.util.function.ToLongBiFunction;
 import java.util.function.ToLongFunction;
 import java.util.stream.Stream;
-import jdk.internal.misc.Unsafe;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * A hash table supporting full concurrency of retrievals and
@@ -159,7 +162,8 @@
  * ordering, or on any other objects or values that may transiently
  * change while computation is in progress; and except for forEach
  * actions, should ideally be side-effect-free. Bulk operations on
- * {@link Map.Entry} objects do not support method {@code setValue}.
+ * {@link java.util.Map.Entry} objects do not support method {@code
+ * setValue}.
  *
  * <ul>
  * <li>forEach: Performs a given action on each element.
@@ -252,10 +256,6 @@
  *
  * <p>All arguments to all task methods must be non-null.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
@@ -297,7 +297,7 @@
      * Table accesses require volatile/atomic reads, writes, and
      * CASes.  Because there is no other way to arrange this without
      * adding further indirections, we use intrinsics
-     * (jdk.internal.misc.Unsafe) operations.
+     * (sun.misc.Unsafe) operations.
      *
      * We use the top (sign) bit of Node hash fields for control
      * purposes -- it is available anyway because of addressing
@@ -628,14 +628,10 @@
         volatile V val;
         volatile Node<K,V> next;
 
-        Node(int hash, K key, V val) {
+        Node(int hash, K key, V val, Node<K,V> next) {
             this.hash = hash;
             this.key = key;
             this.val = val;
-        }
-
-        Node(int hash, K key, V val, Node<K,V> next) {
-            this(hash, key, val);
             this.next = next;
         }
 
@@ -702,7 +698,12 @@
      * See Hackers Delight, sec 3.2
      */
     private static final int tableSizeFor(int c) {
-        int n = -1 >>> Integer.numberOfLeadingZeros(c - 1);
+        int n = c - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
     }
 
@@ -712,12 +713,12 @@
      */
     static Class<?> comparableClassFor(Object x) {
         if (x instanceof Comparable) {
-            Class<?> c; Type[] ts, as; ParameterizedType p;
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
             if ((c = x.getClass()) == String.class) // bypass checks
                 return c;
             if ((ts = c.getGenericInterfaces()) != null) {
-                for (Type t : ts) {
-                    if ((t instanceof ParameterizedType) &&
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
                         ((p = (ParameterizedType)t).getRawType() ==
                          Comparable.class) &&
                         (as = p.getActualTypeArguments()) != null &&
@@ -742,7 +743,7 @@
     /* ---------------- Table element access -------------- */
 
     /*
-     * Atomic access methods are used for table elements as well as
+     * Volatile access methods are used for table elements as well as
      * elements of in-progress next table while resizing.  All uses of
      * the tab arguments must be null checked by callers.  All callers
      * also paranoically precheck that tab's length is not zero (or an
@@ -752,21 +753,23 @@
      * errors by users, these checks must operate on local variables,
      * which accounts for some odd-looking inline assignments below.
      * Note that calls to setTabAt always occur within locked regions,
-     * and so require only release ordering.
+     * and so in principle require only release ordering, not
+     * full volatile semantics, but are currently coded as volatile
+     * writes to be conservative.
      */
 
     @SuppressWarnings("unchecked")
     static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
-        return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
+        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
     }
 
     static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                         Node<K,V> c, Node<K,V> v) {
-        return U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
     }
 
     static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
-        U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
+        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
     }
 
     /* ---------------- Fields -------------- */
@@ -839,7 +842,12 @@
      * elements is negative
      */
     public ConcurrentHashMap(int initialCapacity) {
-        this(initialCapacity, LOAD_FACTOR, 1);
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException();
+        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
+                   MAXIMUM_CAPACITY :
+                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
+        this.sizeCtl = cap;
     }
 
     /**
@@ -873,8 +881,8 @@
 
     /**
      * Creates a new, empty map with an initial table size based on
-     * the given number of elements ({@code initialCapacity}), initial
-     * table density ({@code loadFactor}), and number of concurrently
+     * the given number of elements ({@code initialCapacity}), table
+     * density ({@code loadFactor}), and number of concurrently
      * updating threads ({@code concurrencyLevel}).
      *
      * @param initialCapacity the initial capacity. The implementation
@@ -1012,20 +1020,16 @@
         int hash = spread(key.hashCode());
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh; K fk; V fv;
+            Node<K,V> f; int n, i, fh;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
-                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
+                if (casTabAt(tab, i, null,
+                             new Node<K,V>(hash, key, value, null)))
                     break;                   // no lock when adding to empty bin
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
-            else if (onlyIfAbsent // check first node without acquiring lock
-                     && fh == hash
-                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
-                     && (fv = f.val) != null)
-                return fv;
             else {
                 V oldVal = null;
                 synchronized (f) {
@@ -1044,7 +1048,8 @@
                                 }
                                 Node<K,V> pred = e;
                                 if ((e = e.next) == null) {
-                                    pred.next = new Node<K,V>(hash, key, value);
+                                    pred.next = new Node<K,V>(hash, key,
+                                                              value, null);
                                     break;
                                 }
                             }
@@ -1240,8 +1245,7 @@
     @dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
     public Set<K> keySet() {
         KeySetView<K,V> ks;
-        if ((ks = keySet) != null) return ks;
-        return keySet = new KeySetView<K,V>(this, null);
+        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
     }
 
     /**
@@ -1264,8 +1268,7 @@
      */
     public Collection<V> values() {
         ValuesView<K,V> vs;
-        if ((vs = values) != null) return vs;
-        return values = new ValuesView<K,V>(this);
+        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
     }
 
     /**
@@ -1287,8 +1290,7 @@
      */
     public Set<Map.Entry<K,V>> entrySet() {
         EntrySetView<K,V> es;
-        if ((es = entrySet) != null) return es;
-        return entrySet = new EntrySetView<K,V>(this);
+        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
     }
 
     /**
@@ -1389,8 +1391,8 @@
     }
 
     /**
-     * Saves this map to a stream (that is, serializes it).
-     *
+     * Saves the state of the {@code ConcurrentHashMap} instance to a
+     * stream (i.e., serializes it).
      * @param s the stream
      * @throws java.io.IOException if an I/O error occurs
      * @serialData
@@ -1434,7 +1436,7 @@
     }
 
     /**
-     * Reconstitutes this map from a stream (that is, deserializes it).
+     * Reconstitutes the instance from a stream (that is, deserializes it).
      * @param s the stream
      * @throws ClassNotFoundException if the class of a serialized object
      *         could not be found
@@ -1468,9 +1470,13 @@
         if (size == 0L)
             sizeCtl = 0;
         else {
-            long ts = (long)(1.0 + size / LOAD_FACTOR);
-            int n = (ts >= (long)MAXIMUM_CAPACITY) ?
-                MAXIMUM_CAPACITY : tableSizeFor((int)ts);
+            int n;
+            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
+                n = MAXIMUM_CAPACITY;
+            else {
+                int sz = (int)size;
+                n = tableSizeFor(sz + (sz >>> 1) + 1);
+            }
             @SuppressWarnings("unchecked")
             Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
             int mask = n - 1;
@@ -1697,7 +1703,7 @@
         V val = null;
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh; K fk; V fv;
+            Node<K,V> f; int n, i, fh;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
@@ -1708,7 +1714,7 @@
                         Node<K,V> node = null;
                         try {
                             if ((val = mappingFunction.apply(key)) != null)
-                                node = new Node<K,V>(h, key, val);
+                                node = new Node<K,V>(h, key, val, null);
                         } finally {
                             setTabAt(tab, i, node);
                         }
@@ -1719,10 +1725,6 @@
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
-            else if (fh == h    // check first node without acquiring lock
-                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
-                     && (fv = f.val) != null)
-                return fv;
             else {
                 boolean added = false;
                 synchronized (f) {
@@ -1743,7 +1745,7 @@
                                         if (pred.next != null)
                                             throw new IllegalStateException("Recursive update");
                                         added = true;
-                                        pred.next = new Node<K,V>(h, key, val);
+                                        pred.next = new Node<K,V>(h, key, val, null);
                                     }
                                     break;
                                 }
@@ -1912,7 +1914,7 @@
                         try {
                             if ((val = remappingFunction.apply(key, null)) != null) {
                                 delta = 1;
-                                node = new Node<K,V>(h, key, val);
+                                node = new Node<K,V>(h, key, val, null);
                             }
                         } finally {
                             setTabAt(tab, i, node);
@@ -1954,7 +1956,8 @@
                                         if (pred.next != null)
                                             throw new IllegalStateException("Recursive update");
                                         delta = 1;
-                                        pred.next = new Node<K,V>(h, key, val);
+                                        pred.next =
+                                            new Node<K,V>(h, key, val, null);
                                     }
                                     break;
                                 }
@@ -2032,7 +2035,7 @@
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
-                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
                     delta = 1;
                     val = value;
                     break;
@@ -2067,7 +2070,8 @@
                                 if ((e = e.next) == null) {
                                     delta = 1;
                                     val = value;
-                                    pred.next = new Node<K,V>(h, key, val);
+                                    pred.next =
+                                        new Node<K,V>(h, key, val, null);
                                     break;
                                 }
                             }
@@ -2228,7 +2232,7 @@
     static final class ForwardingNode<K,V> extends Node<K,V> {
         final Node<K,V>[] nextTable;
         ForwardingNode(Node<K,V>[] tab) {
-            super(MOVED, null, null);
+            super(MOVED, null, null, null);
             this.nextTable = tab;
         }
 
@@ -2264,7 +2268,7 @@
      */
     static final class ReservationNode<K,V> extends Node<K,V> {
         ReservationNode() {
-            super(RESERVED, null, null);
+            super(RESERVED, null, null, null);
         }
 
         Node<K,V> find(int h, Object k) {
@@ -2290,7 +2294,7 @@
         while ((tab = table) == null || tab.length == 0) {
             if ((sc = sizeCtl) < 0)
                 Thread.yield(); // lost initialization race; just spin
-            else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
+            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                 try {
                     if ((tab = table) == null || tab.length == 0) {
                         int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@@ -2319,15 +2323,15 @@
      * @param check if <0, don't check resize, if <= 1 only check if uncontended
      */
     private final void addCount(long x, int check) {
-        CounterCell[] cs; long b, s;
-        if ((cs = counterCells) != null ||
-            !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
-            CounterCell c; long v; int m;
+        CounterCell[] as; long b, s;
+        if ((as = counterCells) != null ||
+            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            CounterCell a; long v; int m;
             boolean uncontended = true;
-            if (cs == null || (m = cs.length - 1) < 0 ||
-                (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
                 !(uncontended =
-                  U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
+                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
                 fullAddCount(x, uncontended);
                 return;
             }
@@ -2345,10 +2349,10 @@
                         sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                         transferIndex <= 0)
                         break;
-                    if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
+                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                         transfer(tab, nt);
                 }
-                else if (U.compareAndSetInt(this, SIZECTL, sc,
+                else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                              (rs << RESIZE_STAMP_SHIFT) + 2))
                     transfer(tab, null);
                 s = sumCount();
@@ -2369,7 +2373,7 @@
                 if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                     sc == rs + MAX_RESIZERS || transferIndex <= 0)
                     break;
-                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
+                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
                     transfer(tab, nextTab);
                     break;
                 }
@@ -2392,7 +2396,7 @@
             Node<K,V>[] tab = table; int n;
             if (tab == null || (n = tab.length) == 0) {
                 n = (sc > c) ? sc : c;
-                if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
+                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                     try {
                         if (table == tab) {
                             @SuppressWarnings("unchecked")
@@ -2409,7 +2413,7 @@
                 break;
             else if (tab == table) {
                 int rs = resizeStamp(n);
-                if (U.compareAndSetInt(this, SIZECTL, sc,
+                if (U.compareAndSwapInt(this, SIZECTL, sc,
                                         (rs << RESIZE_STAMP_SHIFT) + 2))
                     transfer(tab, null);
             }
@@ -2450,7 +2454,7 @@
                     i = -1;
                     advance = false;
                 }
-                else if (U.compareAndSetInt
+                else if (U.compareAndSwapInt
                          (this, TRANSFERINDEX, nextIndex,
                           nextBound = (nextIndex > stride ?
                                        nextIndex - stride : 0))) {
@@ -2467,7 +2471,7 @@
                     sizeCtl = (n << 1) - (n >>> 1);
                     return;
                 }
-                if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                     if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                         return;
                     finishing = advance = true;
@@ -2567,12 +2571,13 @@
     }
 
     final long sumCount() {
-        CounterCell[] cs = counterCells;
+        CounterCell[] as = counterCells; CounterCell a;
         long sum = baseCount;
-        if (cs != null) {
-            for (CounterCell c : cs)
-                if (c != null)
-                    sum += c.value;
+        if (as != null) {
+            for (int i = 0; i < as.length; ++i) {
+                if ((a = as[i]) != null)
+                    sum += a.value;
+            }
         }
         return sum;
     }
@@ -2587,13 +2592,13 @@
         }
         boolean collide = false;                // True if last slot nonempty
         for (;;) {
-            CounterCell[] cs; CounterCell c; int n; long v;
-            if ((cs = counterCells) != null && (n = cs.length) > 0) {
-                if ((c = cs[(n - 1) & h]) == null) {
+            CounterCell[] as; CounterCell a; int n; long v;
+            if ((as = counterCells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
                     if (cellsBusy == 0) {            // Try to attach new Cell
                         CounterCell r = new CounterCell(x); // Optimistic create
                         if (cellsBusy == 0 &&
-                            U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                             boolean created = false;
                             try {               // Recheck under lock
                                 CounterCell[] rs; int m, j;
@@ -2615,17 +2620,21 @@
                 }
                 else if (!wasUncontended)       // CAS already known to fail
                     wasUncontended = true;      // Continue after rehash
-                else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
+                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                     break;
-                else if (counterCells != cs || n >= NCPU)
+                else if (counterCells != as || n >= NCPU)
                     collide = false;            // At max size or stale
                 else if (!collide)
                     collide = true;
                 else if (cellsBusy == 0 &&
-                         U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                     try {
-                        if (counterCells == cs) // Expand table unless stale
-                            counterCells = Arrays.copyOf(cs, n << 1);
+                        if (counterCells == as) {// Expand table unless stale
+                            CounterCell[] rs = new CounterCell[n << 1];
+                            for (int i = 0; i < n; ++i)
+                                rs[i] = as[i];
+                            counterCells = rs;
+                        }
                     } finally {
                         cellsBusy = 0;
                     }
@@ -2634,11 +2643,11 @@
                 }
                 h = ThreadLocalRandom.advanceProbe(h);
             }
-            else if (cellsBusy == 0 && counterCells == cs &&
-                     U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+            else if (cellsBusy == 0 && counterCells == as &&
+                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                 boolean init = false;
                 try {                           // Initialize table
-                    if (counterCells == cs) {
+                    if (counterCells == as) {
                         CounterCell[] rs = new CounterCell[2];
                         rs[h & 1] = new CounterCell(x);
                         counterCells = rs;
@@ -2650,7 +2659,7 @@
                 if (init)
                     break;
             }
-            else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
+            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
                 break;                          // Fall back on using base
         }
     }
@@ -2688,12 +2697,12 @@
     }
 
     /**
-     * Returns a list of non-TreeNodes replacing those in given list.
+     * Returns a list on non-TreeNodes replacing those in given list.
      */
     static <K,V> Node<K,V> untreeify(Node<K,V> b) {
         Node<K,V> hd = null, tl = null;
         for (Node<K,V> q = b; q != null; q = q.next) {
-            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
+            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
             if (tl == null)
                 hd = p;
             else
@@ -2799,7 +2808,7 @@
          * Creates bin with initial set of nodes headed by b.
          */
         TreeBin(TreeNode<K,V> b) {
-            super(TREEBIN, null, null);
+            super(TREEBIN, null, null, null);
             this.first = b;
             TreeNode<K,V> r = null;
             for (TreeNode<K,V> x = b, next; x != null; x = next) {
@@ -2846,7 +2855,7 @@
          * Acquires write lock for tree restructuring.
          */
         private final void lockRoot() {
-            if (!U.compareAndSetInt(this, LOCKSTATE, 0, WRITER))
+            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
                 contendedLock(); // offload to separate method
         }
 
@@ -2864,14 +2873,14 @@
             boolean waiting = false;
             for (int s;;) {
                 if (((s = lockState) & ~WAITER) == 0) {
-                    if (U.compareAndSetInt(this, LOCKSTATE, s, WRITER)) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
                         if (waiting)
                             waiter = null;
                         return;
                     }
                 }
                 else if ((s & WAITER) == 0) {
-                    if (U.compareAndSetInt(this, LOCKSTATE, s, s | WAITER)) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
                         waiting = true;
                         waiter = Thread.currentThread();
                     }
@@ -2896,7 +2905,7 @@
                             return e;
                         e = e.next;
                     }
-                    else if (U.compareAndSetInt(this, LOCKSTATE, s,
+                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
                                                  s + READER)) {
                         TreeNode<K,V> r, p;
                         try {
@@ -3293,9 +3302,16 @@
             return true;
         }
 
-        private static final Unsafe U = Unsafe.getUnsafe();
-        private static final long LOCKSTATE
-                = U.objectFieldOffset(TreeBin.class, "lockState");
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long LOCKSTATE;
+        static {
+            try {
+                LOCKSTATE = U.objectFieldOffset
+                    (TreeBin.class.getDeclaredField("lockState"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /* ----------------Table Traversal -------------- */
@@ -3449,9 +3465,9 @@
 
     static final class KeyIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<K>, Enumeration<K> {
-        KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
+        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
                     ConcurrentHashMap<K,V> map) {
-            super(tab, size, index, limit, map);
+            super(tab, index, size, limit, map);
         }
 
         public final K next() {
@@ -3469,9 +3485,9 @@
 
     static final class ValueIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<V>, Enumeration<V> {
-        ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
+        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
                       ConcurrentHashMap<K,V> map) {
-            super(tab, size, index, limit, map);
+            super(tab, index, size, limit, map);
         }
 
         public final V next() {
@@ -3489,9 +3505,9 @@
 
     static final class EntryIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<Map.Entry<K,V>> {
-        EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
+        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
                       ConcurrentHashMap<K,V> map) {
-            super(tab, size, index, limit, map);
+            super(tab, index, size, limit, map);
         }
 
         public final Map.Entry<K,V> next() {
@@ -4542,24 +4558,14 @@
             return true;
         }
 
-        public boolean removeAll(Collection<?> c) {
+        public final boolean removeAll(Collection<?> c) {
             if (c == null) throw new NullPointerException();
             boolean modified = false;
-            // Use (c instanceof Set) as a hint that lookup in c is as
-            // efficient as this view
-            Node<K,V>[] t;
-            if ((t = map.table) == null) {
-                return false;
-            } else if (c instanceof Set<?> && c.size() > t.length) {
-                for (Iterator<?> it = iterator(); it.hasNext(); ) {
-                    if (c.contains(it.next())) {
-                        it.remove();
-                        modified = true;
-                    }
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
                 }
-            } else {
-                for (Object e : c)
-                    modified |= remove(e);
             }
             return modified;
         }
@@ -4745,18 +4751,6 @@
             throw new UnsupportedOperationException();
         }
 
-        @Override public boolean removeAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean modified = false;
-            for (Iterator<V> it = iterator(); it.hasNext();) {
-                if (c.contains(it.next())) {
-                    it.remove();
-                    modified = true;
-                }
-            }
-            return modified;
-        }
-
         public boolean removeIf(Predicate<? super V> filter) {
             return map.removeValueIf(filter);
         }
@@ -6350,7 +6344,7 @@
     }
 
     // Unsafe mechanics
-    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
     private static final long SIZECTL;
     private static final long TRANSFERINDEX;
     private static final long BASECOUNT;
@@ -6360,29 +6354,30 @@
     private static final int ASHIFT;
 
     static {
-        SIZECTL = U.objectFieldOffset
-            (ConcurrentHashMap.class, "sizeCtl");
-        TRANSFERINDEX = U.objectFieldOffset
-            (ConcurrentHashMap.class, "transferIndex");
-        BASECOUNT = U.objectFieldOffset
-            (ConcurrentHashMap.class, "baseCount");
-        CELLSBUSY = U.objectFieldOffset
-            (ConcurrentHashMap.class, "cellsBusy");
+        try {
+            SIZECTL = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
+            TRANSFERINDEX = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
+            BASECOUNT = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
+            CELLSBUSY = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
 
-        CELLVALUE = U.objectFieldOffset
-            (CounterCell.class, "value");
+            CELLVALUE = U.objectFieldOffset
+                (CounterCell.class.getDeclaredField("value"));
 
-        ABASE = U.arrayBaseOffset(Node[].class);
-        int scale = U.arrayIndexScale(Node[].class);
-        if ((scale & (scale - 1)) != 0)
-            throw new ExceptionInInitializerError("array index scale not a power of two");
-        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+            ABASE = U.arrayBaseOffset(Node[].class);
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
 
         // Reduce the risk of rare disastrous classloading in first call to
         // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
-
-        // Eager class load observed to help JIT during startup
-        ensureLoaded = ReservationNode.class;
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 91ddabd..3edde54 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.AbstractCollection;
 import java.util.Arrays;
 import java.util.Collection;
@@ -48,7 +46,10 @@
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
@@ -67,12 +68,12 @@
  * asynchronous nature of these deques, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- *
- * <p>Bulk operations that add, remove, or examine multiple elements,
- * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
- * are <em>not</em> guaranteed to be performed atomically.
- * For example, a {@code forEach} traversal concurrent with an {@code
- * addAll} operation might observe only some of the added elements.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Deque} and {@link Iterator} interfaces.
@@ -84,10 +85,6 @@
  * actions subsequent to the access or removal of that element from
  * the {@code ConcurrentLinkedDeque} in another thread.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.7
  * @author Doug Lea
  * @author Martin Buchholz
@@ -231,16 +228,15 @@
      *
      * The implementation is completely directionally symmetrical,
      * except that most public methods that iterate through the list
-     * follow next pointers, in the "forward" direction.
+     * follow next pointers ("forward" direction).
      *
-     * We believe (without full proof) that all single-element Deque
-     * operations that operate directly at the two ends of the Deque
-     * (e.g., addFirst, peekLast, pollLast) are linearizable (see
-     * Herlihy and Shavit's book).  However, some combinations of
+     * We believe (without full proof) that all single-element deque
+     * operations (e.g., addFirst, peekLast, pollLast) are linearizable
+     * (see Herlihy and Shavit's book).  However, some combinations of
      * operations are known not to be linearizable.  In particular,
-     * when an addFirst(A) is racing with pollFirst() removing B, it
-     * is possible for an observer iterating over the elements to
-     * observe first [A B C] and then [A C], even though no interior
+     * when an addFirst(A) is racing with pollFirst() removing B, it is
+     * possible for an observer iterating over the elements to observe
+     * A B C and subsequently observe A C, even though no interior
      * removes are ever performed.  Nevertheless, iterators behave
      * reasonably, providing the "weakly consistent" guarantees.
      *
@@ -296,23 +292,64 @@
         volatile Node<E> prev;
         volatile E item;
         volatile Node<E> next;
-    }
 
-    /**
-     * Returns a new node holding item.  Uses relaxed write because item
-     * can only be seen after piggy-backing publication via CAS.
-     */
-    static <E> Node<E> newNode(E item) {
-        Node<E> node = new Node<E>();
-        ITEM.set(node, item);
-        return node;
+        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext or casPrev.
+         */
+        Node(E item) {
+            U.putObject(this, ITEM, item);
+        }
+
+        boolean casItem(E cmp, E val) {
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        void lazySetNext(Node<E> val) {
+            U.putOrderedObject(this, NEXT, val);
+        }
+
+        boolean casNext(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        void lazySetPrev(Node<E> val) {
+            U.putOrderedObject(this, PREV, val);
+        }
+
+        boolean casPrev(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, PREV, cmp, val);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long PREV;
+        private static final long ITEM;
+        private static final long NEXT;
+
+        static {
+            try {
+                PREV = U.objectFieldOffset
+                    (Node.class.getDeclaredField("prev"));
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
      * Links e as first element.
      */
     private void linkFirst(E e) {
-        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
 
         restartFromHead:
         for (;;)
@@ -326,13 +363,13 @@
                     continue restartFromHead;
                 else {
                     // p is first node
-                    NEXT.set(newNode, p); // CAS piggyback
-                    if (PREV.compareAndSet(p, null, newNode)) {
+                    newNode.lazySetNext(p); // CAS piggyback
+                    if (p.casPrev(null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != h) // hop two nodes at a time; failure is OK
-                            HEAD.weakCompareAndSet(this, h, newNode);
+                        if (p != h) // hop two nodes at a time
+                            casHead(h, newNode);  // Failure is OK.
                         return;
                     }
                     // Lost CAS race to another thread; re-read prev
@@ -344,7 +381,7 @@
      * Links e as last element.
      */
     private void linkLast(E e) {
-        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
 
         restartFromTail:
         for (;;)
@@ -358,13 +395,13 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    PREV.set(newNode, p); // CAS piggyback
-                    if (NEXT.compareAndSet(p, null, newNode)) {
+                    newNode.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != t) // hop two nodes at a time; failure is OK
-                            TAIL.weakCompareAndSet(this, t, newNode);
+                        if (p != t) // hop two nodes at a time
+                            casTail(t, newNode);  // Failure is OK.
                         return;
                     }
                     // Lost CAS race to another thread; re-read next
@@ -479,8 +516,8 @@
                 updateTail(); // Ensure x is not reachable from tail
 
                 // Finally, actually gc-unlink
-                PREV.setRelease(x, isFirst ? prevTerminator() : x);
-                NEXT.setRelease(x, isLast  ? nextTerminator() : x);
+                x.lazySetPrev(isFirst ? prevTerminator() : x);
+                x.lazySetNext(isLast  ? nextTerminator() : x);
             }
         }
     }
@@ -494,8 +531,7 @@
         // assert first.item == null;
         for (Node<E> o = null, p = next, q;;) {
             if (p.item != null || (q = p.next) == null) {
-                if (o != null && p.prev != p &&
-                    NEXT.compareAndSet(first, next, p)) {
+                if (o != null && p.prev != p && first.casNext(next, p)) {
                     skipDeletedPredecessors(p);
                     if (first.prev == null &&
                         (p.next == null || p.item != null) &&
@@ -505,8 +541,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        NEXT.setRelease(o, o);
-                        PREV.setRelease(o, prevTerminator());
+                        o.lazySetNext(o);
+                        o.lazySetPrev(prevTerminator());
                     }
                 }
                 return;
@@ -529,8 +565,7 @@
         // assert last.item == null;
         for (Node<E> o = null, p = prev, q;;) {
             if (p.item != null || (q = p.prev) == null) {
-                if (o != null && p.next != p &&
-                    PREV.compareAndSet(last, prev, p)) {
+                if (o != null && p.next != p && last.casPrev(prev, p)) {
                     skipDeletedSuccessors(p);
                     if (last.next == null &&
                         (p.prev == null || p.item != null) &&
@@ -540,8 +575,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        PREV.setRelease(o, o);
-                        NEXT.setRelease(o, nextTerminator());
+                        o.lazySetPrev(o);
+                        o.lazySetNext(nextTerminator());
                     }
                 }
                 return;
@@ -572,7 +607,7 @@
                     (q = (p = q).prev) == null) {
                     // It is possible that p is PREV_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (HEAD.compareAndSet(this, h, p))
+                    if (casHead(h, p))
                         return;
                     else
                         continue restartFromHead;
@@ -602,7 +637,7 @@
                     (q = (p = q).next) == null) {
                     // It is possible that p is NEXT_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (TAIL.compareAndSet(this, t, p))
+                    if (casTail(t, p))
                         return;
                     else
                         continue restartFromTail;
@@ -640,7 +675,7 @@
             }
 
             // found active CAS target
-            if (prev == p || PREV.compareAndSet(x, prev, p))
+            if (prev == p || x.casPrev(prev, p))
                 return;
 
         } while (x.item != null || x.next == null);
@@ -671,7 +706,7 @@
             }
 
             // found active CAS target
-            if (next == p || NEXT.compareAndSet(x, next, p))
+            if (next == p || x.casNext(next, p))
                 return;
 
         } while (x.item != null || x.prev == null);
@@ -684,9 +719,8 @@
      */
     final Node<E> succ(Node<E> p) {
         // TODO: should we skip deleted nodes here?
-        if (p == (p = p.next))
-            p = first();
-        return p;
+        Node<E> q = p.next;
+        return (p == q) ? first() : q;
     }
 
     /**
@@ -695,9 +729,8 @@
      * stale pointer that is now off the list.
      */
     final Node<E> pred(Node<E> p) {
-        if (p == (p = p.prev))
-            p = last();
-        return p;
+        Node<E> q = p.prev;
+        return (p == q) ? last() : q;
     }
 
     /**
@@ -718,7 +751,7 @@
                 else if (p == h
                          // It is possible that p is PREV_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || HEAD.compareAndSet(this, h, p))
+                         || casHead(h, p))
                     return p;
                 else
                     continue restartFromHead;
@@ -743,7 +776,7 @@
                 else if (p == t
                          // It is possible that p is NEXT_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || TAIL.compareAndSet(this, t, p))
+                         || casTail(t, p))
                     return p;
                 else
                     continue restartFromTail;
@@ -769,7 +802,7 @@
      * Constructs an empty deque.
      */
     public ConcurrentLinkedDeque() {
-        head = tail = new Node<E>();
+        head = tail = new Node<E>(null);
     }
 
     /**
@@ -785,12 +818,12 @@
         // Copy c into a private chain of Nodes
         Node<E> h = null, t = null;
         for (E e : c) {
-            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
             if (h == null)
                 h = t = newNode;
             else {
-                NEXT.set(t, newNode);
-                PREV.set(newNode, t);
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
                 t = newNode;
             }
         }
@@ -803,12 +836,12 @@
     private void initHeadTail(Node<E> h, Node<E> t) {
         if (h == t) {
             if (h == null)
-                h = t = new Node<E>();
+                h = t = new Node<E>(null);
             else {
                 // Avoid edge case of a single Node with non-null item.
-                Node<E> newNode = new Node<E>();
-                NEXT.set(t, newNode);
-                PREV.set(newNode, t);
+                Node<E> newNode = new Node<E>(null);
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
                 t = newNode;
             }
         }
@@ -867,33 +900,21 @@
     }
 
     public E peekFirst() {
-        restart: for (;;) {
-            E item;
-            Node<E> first = first(), p = first;
-            while ((item = p.item) == null) {
-                if (p == (p = p.next)) continue restart;
-                if (p == null)
-                    break;
-            }
-            // recheck for linearizability
-            if (first.prev != null) continue restart;
-            return item;
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
         }
+        return null;
     }
 
     public E peekLast() {
-        restart: for (;;) {
-            E item;
-            Node<E> last = last(), p = last;
-            while ((item = p.item) == null) {
-                if (p == (p = p.prev)) continue restart;
-                if (p == null)
-                    break;
-            }
-            // recheck for linearizability
-            if (last.next != null) continue restart;
-            return item;
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
         }
+        return null;
     }
 
     /**
@@ -911,45 +932,25 @@
     }
 
     public E pollFirst() {
-        restart: for (;;) {
-            for (Node<E> first = first(), p = first;;) {
-                final E item;
-                if ((item = p.item) != null) {
-                    // recheck for linearizability
-                    if (first.prev != null) continue restart;
-                    if (ITEM.compareAndSet(p, item, null)) {
-                        unlink(p);
-                        return item;
-                    }
-                }
-                if (p == (p = p.next)) continue restart;
-                if (p == null) {
-                    if (first.prev != null) continue restart;
-                    return null;
-                }
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
             }
         }
+        return null;
     }
 
     public E pollLast() {
-        restart: for (;;) {
-            for (Node<E> last = last(), p = last;;) {
-                final E item;
-                if ((item = p.item) != null) {
-                    // recheck for linearizability
-                    if (last.next != null) continue restart;
-                    if (ITEM.compareAndSet(p, item, null)) {
-                        unlink(p);
-                        return item;
-                    }
-                }
-                if (p == (p = p.prev)) continue restart;
-                if (p == null) {
-                    if (last.next != null) continue restart;
-                    return null;
-                }
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
             }
         }
+        return null;
     }
 
     /**
@@ -1029,10 +1030,8 @@
     public boolean removeFirstOccurrence(Object o) {
         Objects.requireNonNull(o);
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            final E item;
-            if ((item = p.item) != null
-                && o.equals(item)
-                && ITEM.compareAndSet(p, item, null)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1055,10 +1054,8 @@
     public boolean removeLastOccurrence(Object o) {
         Objects.requireNonNull(o);
         for (Node<E> p = last(); p != null; p = pred(p)) {
-            final E item;
-            if ((item = p.item) != null
-                && o.equals(item)
-                && ITEM.compareAndSet(p, item, null)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1077,8 +1074,8 @@
     public boolean contains(Object o) {
         if (o != null) {
             for (Node<E> p = first(); p != null; p = succ(p)) {
-                final E item;
-                if ((item = p.item) != null && o.equals(item))
+                E item = p.item;
+                if (item != null && o.equals(item))
                     return true;
             }
         }
@@ -1111,14 +1108,14 @@
      * @return the number of elements in this deque
      */
     public int size() {
-        restart: for (;;) {
+        restartFromHead: for (;;) {
             int count = 0;
             for (Node<E> p = first(); p != null;) {
                 if (p.item != null)
                     if (++count == Integer.MAX_VALUE)
                         break;  // @see Collection.size()
                 if (p == (p = p.next))
-                    continue restart;
+                    continue restartFromHead;
             }
             return count;
         }
@@ -1162,12 +1159,12 @@
         // Copy c into a private chain of Nodes
         Node<E> beginningOfTheEnd = null, last = null;
         for (E e : c) {
-            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
             else {
-                NEXT.set(last, newNode);
-                PREV.set(newNode, last);
+                last.lazySetNext(newNode);
+                newNode.lazySetPrev(last);
                 last = newNode;
             }
         }
@@ -1187,16 +1184,16 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    PREV.set(beginningOfTheEnd, p); // CAS piggyback
-                    if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
+                    beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, beginningOfTheEnd)) {
                         // Successful CAS is the linearization point
                         // for all elements to be added to this deque.
-                        if (!TAIL.weakCompareAndSet(this, t, last)) {
+                        if (!casTail(t, last)) {
                             // Try a little harder to update tail,
                             // since we may be adding many elements.
                             t = tail;
                             if (last.next == null)
-                                TAIL.weakCompareAndSet(this, t, last);
+                                casTail(t, last);
                         }
                         return true;
                     }
@@ -1215,12 +1212,12 @@
 
     public String toString() {
         String[] a = null;
-        restart: for (;;) {
+        restartFromHead: for (;;) {
             int charLength = 0;
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                final E item;
-                if ((item = p.item) != null) {
+                E item = p.item;
+                if (item != null) {
                     if (a == null)
                         a = new String[4];
                     else if (size == a.length)
@@ -1230,7 +1227,7 @@
                     charLength += s.length();
                 }
                 if (p == (p = p.next))
-                    continue restart;
+                    continue restartFromHead;
             }
 
             if (size == 0)
@@ -1242,11 +1239,11 @@
 
     private Object[] toArrayInternal(Object[] a) {
         Object[] x = a;
-        restart: for (;;) {
+        restartFromHead: for (;;) {
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                final E item;
-                if ((item = p.item) != null) {
+                E item = p.item;
+                if (item != null) {
                     if (x == null)
                         x = new Object[4];
                     else if (size == x.length)
@@ -1254,7 +1251,7 @@
                     x[size++] = item;
                 }
                 if (p == (p = p.next))
-                    continue restart;
+                    continue restartFromHead;
             }
             if (x == null)
                 return new Object[0];
@@ -1398,8 +1395,8 @@
                     nextItem = null;
                     break;
                 }
-                final E item;
-                if ((item = p.item) != null) {
+                E item = p.item;
+                if (item != null) {
                     nextNode = p;
                     nextItem = item;
                     break;
@@ -1429,75 +1426,90 @@
 
     /** Forward iterator */
     private class Itr extends AbstractItr {
-        Itr() {}                        // prevent access constructor creation
         Node<E> startNode() { return first(); }
         Node<E> nextNode(Node<E> p) { return succ(p); }
     }
 
     /** Descending iterator */
     private class DescendingItr extends AbstractItr {
-        DescendingItr() {}              // prevent access constructor creation
         Node<E> startNode() { return last(); }
         Node<E> nextNode(Node<E> p) { return pred(p); }
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    final class CLDSpliterator implements Spliterator<E> {
+    static final class CLDSpliterator<E> implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
+        CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
+            this.queue = queue;
+        }
 
         public Spliterator<E> trySplit() {
-            Node<E> p, q;
-            if ((p = current()) == null || (q = p.next) == null)
-                return null;
-            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
-            Object[] a = null;
-            do {
-                final E e;
-                if ((e = p.item) != null) {
-                    if (a == null)
-                        a = new Object[n];
-                    a[i++] = e;
+            Node<E> p;
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                if (p.item == null && p == (p = p.next))
+                    current = p = q.first();
+                if (p != null && p.next != null) {
+                    Object[] a = new Object[n];
+                    int i = 0;
+                    do {
+                        if ((a[i] = p.item) != null)
+                            ++i;
+                        if (p == (p = p.next))
+                            p = q.first();
+                    } while (p != null && i < n);
+                    if ((current = p) == null)
+                        exhausted = true;
+                    if (i > 0) {
+                        batch = i;
+                        return Spliterators.spliterator
+                            (a, 0, i, (Spliterator.ORDERED |
+                                       Spliterator.NONNULL |
+                                       Spliterator.CONCURRENT));
+                    }
                 }
-                if (p == (p = q))
-                    p = first();
-            } while (p != null && (q = p.next) != null && i < n);
-            setCurrent(p);
-            return (i == 0) ? null :
-                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
-                                                   Spliterator.NONNULL |
-                                                   Spliterator.CONCURRENT));
+            }
+            return null;
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
             Node<E> p;
-            if ((p = current()) != null) {
-                current = null;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
                 exhausted = true;
                 do {
-                    final E e;
-                    if ((e = p.item) != null)
-                        action.accept(e);
+                    E e = p.item;
                     if (p == (p = p.next))
-                        p = first();
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
                 } while (p != null);
             }
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
             Node<E> p;
-            if ((p = current()) != null) {
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
                 E e;
                 do {
                     e = p.item;
                     if (p == (p = p.next))
-                        p = first();
+                        p = q.first();
                 } while (e == null && p != null);
-                setCurrent(p);
+                if ((current = p) == null)
+                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -1506,24 +1518,11 @@
             return false;
         }
 
-        private void setCurrent(Node<E> p) {
-            if ((current = p) == null)
-                exhausted = true;
-        }
-
-        private Node<E> current() {
-            Node<E> p;
-            if ((p = current) == null && !exhausted)
-                setCurrent(p = first());
-            return p;
-        }
-
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return (Spliterator.ORDERED |
-                    Spliterator.NONNULL |
-                    Spliterator.CONCURRENT);
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
         }
     }
 
@@ -1544,7 +1543,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new CLDSpliterator();
+        return new CLDSpliterator<E>(this);
     }
 
     /**
@@ -1563,8 +1562,8 @@
 
         // Write out all elements in the proper order.
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            final E item;
-            if ((item = p.item) != null)
+            E item = p.item;
+            if (item != null)
                 s.writeObject(item);
         }
 
@@ -1587,91 +1586,43 @@
         Node<E> h = null, t = null;
         for (Object item; (item = s.readObject()) != null; ) {
             @SuppressWarnings("unchecked")
-            Node<E> newNode = newNode((E) item);
+            Node<E> newNode = new Node<E>((E) item);
             if (h == null)
                 h = t = newNode;
             else {
-                NEXT.set(t, newNode);
-                PREV.set(newNode, t);
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
                 t = newNode;
             }
         }
         initHeadTail(h, t);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
+    // Unsafe mechanics
 
-    /** Implementation of bulk remove methods. */
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        boolean removed = false;
-        for (Node<E> p = first(), succ; p != null; p = succ) {
-            succ = succ(p);
-            final E item;
-            if ((item = p.item) != null
-                && filter.test(item)
-                && ITEM.compareAndSet(p, item, null)) {
-                unlink(p);
-                removed = true;
-            }
-        }
-        return removed;
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        E item;
-        for (Node<E> p = first(); p != null; p = succ(p))
-            if ((item = p.item) != null)
-                action.accept(item);
-    }
-
-    // VarHandle mechanics
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
-    private static final VarHandle PREV;
-    private static final VarHandle NEXT;
-    private static final VarHandle ITEM;
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
     static {
         PREV_TERMINATOR = new Node<Object>();
         PREV_TERMINATOR.next = PREV_TERMINATOR;
         NEXT_TERMINATOR = new Node<Object>();
         NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
-                                   Node.class);
-            TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
-                                   Node.class);
-            PREV = l.findVarHandle(Node.class, "prev", Node.class);
-            NEXT = l.findVarHandle(Node.class, "next", Node.class);
-            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index eac8ee7..7997c60 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
@@ -47,7 +45,10 @@
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
@@ -81,12 +82,12 @@
  * asynchronous nature of these queues, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- *
- * <p>Bulk operations that add, remove, or examine multiple elements,
- * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
- * are <em>not</em> guaranteed to be performed atomically.
- * For example, a {@code forEach} traversal concurrent with an {@code
- * addAll} operation might observe only some of the added elements.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Queue} and {@link Iterator} interfaces.
@@ -98,10 +99,6 @@
  * actions subsequent to the access or removal of that element from
  * the {@code ConcurrentLinkedQueue} in another thread.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -113,7 +110,7 @@
     /*
      * This is a modification of the Michael & Scott algorithm,
      * adapted for a garbage-collected environment, with support for
-     * interior node deletion (to support e.g. remove(Object)).  For
+     * interior node deletion (to support remove(Object)).  For
      * explanation, read the paper.
      *
      * Note that like most non-blocking algorithms in this package,
@@ -161,17 +158,17 @@
      * it is possible for tail to lag behind head (why not)?
      *
      * CASing a Node's item reference to null atomically removes the
-     * element from the queue, leaving a "dead" node that should later
-     * be unlinked (but unlinking is merely an optimization).
-     * Interior element removal methods (other than Iterator.remove())
-     * keep track of the predecessor node during traversal so that the
-     * node can be CAS-unlinked.  Some traversal methods try to unlink
-     * any deleted nodes encountered during traversal.  See comments
-     * in bulkRemove.
+     * element from the queue.  Iterators skip over Nodes with null
+     * items.  Prior implementations of this class had a race between
+     * poll() and remove(Object) where the same element would appear
+     * to be successfully removed by two concurrent operations.  The
+     * method remove(Object) also lazily unlinks deleted Nodes, but
+     * this is merely an optimization.
      *
      * When constructing a Node (before enqueuing it) we avoid paying
-     * for a volatile write to item.  This allows the cost of enqueue
-     * to be "one-and-a-half" CASes.
+     * for a volatile write to item by using Unsafe.putObject instead
+     * of a normal write.  This allows the cost of enqueue to be
+     * "one-and-a-half" CASes.
      *
      * Both head and tail may or may not point to a Node with a
      * non-null item.  If the queue is empty, all items must of course
@@ -181,33 +178,31 @@
      * optimization.
      */
 
-    static final class Node<E> {
+    private static class Node<E> {
         volatile E item;
         volatile Node<E> next;
+    }
 
-        /**
-         * Constructs a node holding item.  Uses relaxed write because
-         * item can only be seen after piggy-backing publication via CAS.
-         */
-        Node(E item) {
-            ITEM.set(this, item);
-        }
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via casNext.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        U.putObject(node, ITEM, item);
+        return node;
+    }
 
-        /** Constructs a dead dummy node. */
-        Node() {}
+    static <E> boolean casItem(Node<E> node, E cmp, E val) {
+        return U.compareAndSwapObject(node, ITEM, cmp, val);
+    }
 
-        void appendRelaxed(Node<E> next) {
-            // assert next != null;
-            // assert this.next == null;
-            NEXT.set(this, next);
-        }
+    static <E> void lazySetNext(Node<E> node, Node<E> val) {
+        U.putOrderedObject(node, NEXT, val);
+    }
 
-        boolean casItem(E cmp, E val) {
-            // assert item == cmp || item == null;
-            // assert cmp != null;
-            // assert val == null;
-            return ITEM.compareAndSet(this, cmp, val);
-        }
+    static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(node, NEXT, cmp, val);
     }
 
     /**
@@ -234,7 +229,7 @@
      * - tail.item may or may not be null.
      * - it is permitted for tail to lag behind head, that is, for tail
      *   to not be reachable from head!
-     * - tail.next may or may not be self-linked.
+     * - tail.next may or may not be self-pointing to tail.
      */
     private transient volatile Node<E> tail;
 
@@ -242,7 +237,7 @@
      * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
      */
     public ConcurrentLinkedQueue() {
-        head = tail = new Node<E>();
+        head = tail = newNode(null);
     }
 
     /**
@@ -257,14 +252,16 @@
     public ConcurrentLinkedQueue(Collection<? extends E> c) {
         Node<E> h = null, t = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (h == null)
                 h = t = newNode;
-            else
-                t.appendRelaxed(t = newNode);
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
         }
         if (h == null)
-            h = t = new Node<E>();
+            h = t = newNode(null);
         head = h;
         tail = t;
     }
@@ -289,8 +286,8 @@
      */
     final void updateHead(Node<E> h, Node<E> p) {
         // assert h != null && p != null && (h == p || h.item == null);
-        if (h != p && HEAD.compareAndSet(this, h, p))
-            NEXT.setRelease(h, h);
+        if (h != p && casHead(h, p))
+            lazySetNext(h, h);
     }
 
     /**
@@ -299,49 +296,8 @@
      * stale pointer that is now off the list.
      */
     final Node<E> succ(Node<E> p) {
-        if (p == (p = p.next))
-            p = head;
-        return p;
-    }
-
-    /**
-     * Tries to CAS pred.next (or head, if pred is null) from c to p.
-     * Caller must ensure that we're not unlinking the trailing node.
-     */
-    private boolean tryCasSuccessor(Node<E> pred, Node<E> c, Node<E> p) {
-        // assert p != null;
-        // assert c.item == null;
-        // assert c != p;
-        if (pred != null)
-            return NEXT.compareAndSet(pred, c, p);
-        if (HEAD.compareAndSet(this, c, p)) {
-            NEXT.setRelease(c, c);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Collapse dead nodes between pred and q.
-     * @param pred the last known live node, or null if none
-     * @param c the first dead node
-     * @param p the last dead node
-     * @param q p.next: the next live node, or null if at end
-     * @return either old pred or p if pred dead or CAS failed
-     */
-    private Node<E> skipDeadNodes(Node<E> pred, Node<E> c, Node<E> p, Node<E> q) {
-        // assert pred != c;
-        // assert p != q;
-        // assert c.item == null;
-        // assert p.item == null;
-        if (q == null) {
-            // Never unlink trailing node.
-            if (c == p) return pred;
-            q = p;
-        }
-        return (tryCasSuccessor(pred, c, q)
-                && (pred == null || ITEM.get(pred) != null))
-            ? pred : p;
+        Node<E> next = p.next;
+        return (p == next) ? head : next;
     }
 
     /**
@@ -352,18 +308,18 @@
      * @throws NullPointerException if the specified element is null
      */
     public boolean offer(E e) {
-        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
 
         for (Node<E> t = tail, p = t;;) {
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (NEXT.compareAndSet(p, null, newNode)) {
+                if (casNext(p, null, newNode)) {
                     // Successful CAS is the linearization point
                     // for e to become an element of this queue,
                     // and for newNode to become "live".
-                    if (p != t) // hop two nodes at a time; failure is OK
-                        TAIL.weakCompareAndSet(this, t, newNode);
+                    if (p != t) // hop two nodes at a time
+                        casTail(t, newNode);  // Failure is OK.
                     return true;
                 }
                 // Lost CAS race to another thread; re-read next
@@ -381,10 +337,12 @@
     }
 
     public E poll() {
-        restartFromHead: for (;;) {
-            for (Node<E> h = head, p = h, q;; p = q) {
-                final E item;
-                if ((item = p.item) != null && p.casItem(item, null)) {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+
+                if (item != null && casItem(p, item, null)) {
                     // Successful CAS is the linearization point
                     // for item to be removed from this queue.
                     if (p != h) // hop two nodes at a time
@@ -397,21 +355,25 @@
                 }
                 else if (p == q)
                     continue restartFromHead;
+                else
+                    p = q;
             }
         }
     }
 
     public E peek() {
-        restartFromHead: for (;;) {
-            for (Node<E> h = head, p = h, q;; p = q) {
-                final E item;
-                if ((item = p.item) != null
-                    || (q = p.next) == null) {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+                if (item != null || (q = p.next) == null) {
                     updateHead(h, p);
                     return item;
                 }
                 else if (p == q)
                     continue restartFromHead;
+                else
+                    p = q;
             }
         }
     }
@@ -425,8 +387,9 @@
      * of losing a race to a concurrent poll().
      */
     Node<E> first() {
-        restartFromHead: for (;;) {
-            for (Node<E> h = head, p = h, q;; p = q) {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
                 boolean hasItem = (p.item != null);
                 if (hasItem || (q = p.next) == null) {
                     updateHead(h, p);
@@ -434,6 +397,8 @@
                 }
                 else if (p == q)
                     continue restartFromHead;
+                else
+                    p = q;
             }
         }
     }
@@ -486,25 +451,14 @@
      * @return {@code true} if this queue contains the specified element
      */
     public boolean contains(Object o) {
-        if (o == null) return false;
-        restartFromHead: for (;;) {
-            for (Node<E> p = head, pred = null; p != null; ) {
-                Node<E> q = p.next;
-                final E item;
-                if ((item = p.item) != null) {
-                    if (o.equals(item))
-                        return true;
-                    pred = p; p = q; continue;
-                }
-                for (Node<E> c = p;; q = p.next) {
-                    if (q == null || q.item != null) {
-                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                    }
-                    if (p == (p = q)) continue restartFromHead;
-                }
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                E item = p.item;
+                if (item != null && o.equals(item))
+                    return true;
             }
-            return false;
         }
+        return false;
     }
 
     /**
@@ -519,27 +473,27 @@
      * @return {@code true} if this queue changed as a result of the call
      */
     public boolean remove(Object o) {
-        if (o == null) return false;
-        restartFromHead: for (;;) {
-            for (Node<E> p = head, pred = null; p != null; ) {
-                Node<E> q = p.next;
-                final E item;
-                if ((item = p.item) != null) {
-                    if (o.equals(item) && p.casItem(item, null)) {
-                        skipDeadNodes(pred, p, p, q);
-                        return true;
+        if (o != null) {
+            Node<E> next, pred = null;
+            for (Node<E> p = first(); p != null; pred = p, p = next) {
+                boolean removed = false;
+                E item = p.item;
+                if (item != null) {
+                    if (!o.equals(item)) {
+                        next = succ(p);
+                        continue;
                     }
-                    pred = p; p = q; continue;
+                    removed = casItem(p, item, null);
                 }
-                for (Node<E> c = p;; q = p.next) {
-                    if (q == null || q.item != null) {
-                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                    }
-                    if (p == (p = q)) continue restartFromHead;
-                }
+
+                next = succ(p);
+                if (pred != null && next != null) // unlink
+                    casNext(pred, p, next);
+                if (removed)
+                    return true;
             }
-            return false;
         }
+        return false;
     }
 
     /**
@@ -562,11 +516,13 @@
         // Copy c into a private chain of Nodes
         Node<E> beginningOfTheEnd = null, last = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
-            else
-                last.appendRelaxed(last = newNode);
+            else {
+                lazySetNext(last, newNode);
+                last = newNode;
+            }
         }
         if (beginningOfTheEnd == null)
             return false;
@@ -576,15 +532,15 @@
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
+                if (casNext(p, null, beginningOfTheEnd)) {
                     // Successful CAS is the linearization point
                     // for all elements to be added to this queue.
-                    if (!TAIL.weakCompareAndSet(this, t, last)) {
+                    if (!casTail(t, last)) {
                         // Try a little harder to update tail,
                         // since we may be adding many elements.
                         t = tail;
                         if (last.next == null)
-                            TAIL.weakCompareAndSet(this, t, last);
+                            casTail(t, last);
                     }
                     return true;
                 }
@@ -608,8 +564,8 @@
             int charLength = 0;
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                final E item;
-                if ((item = p.item) != null) {
+                E item = p.item;
+                if (item != null) {
                     if (a == null)
                         a = new String[4];
                     else if (size == a.length)
@@ -634,8 +590,8 @@
         restartFromHead: for (;;) {
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                final E item;
-                if ((item = p.item) != null) {
+                E item = p.item;
+                if (item != null) {
                     if (x == null)
                         x = new Object[4];
                     else if (size == x.length)
@@ -712,7 +668,7 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        Objects.requireNonNull(a);
+        if (a == null) throw new NullPointerException();
         return (T[]) toArrayInternal(a);
     }
 
@@ -752,7 +708,7 @@
             restartFromHead: for (;;) {
                 Node<E> h, p, q;
                 for (p = h = head;; p = q) {
-                    final E item;
+                    E item;
                     if ((item = p.item) != null) {
                         nextNode = p;
                         nextItem = item;
@@ -788,12 +744,10 @@
                 }
                 // unlink deleted nodes
                 if ((q = succ(p)) != null)
-                    NEXT.compareAndSet(pred, p, q);
+                    casNext(pred, p, q);
             }
         }
 
-        // Default implementation of forEachRemaining is "good enough".
-
         public void remove() {
             Node<E> l = lastRet;
             if (l == null) throw new IllegalStateException();
@@ -819,8 +773,8 @@
 
         // Write out all elements in the proper order.
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            final E item;
-            if ((item = p.item) != null)
+            Object item = p.item;
+            if (item != null)
                 s.writeObject(item);
         }
 
@@ -843,69 +797,91 @@
         Node<E> h = null, t = null;
         for (Object item; (item = s.readObject()) != null; ) {
             @SuppressWarnings("unchecked")
-            Node<E> newNode = new Node<E>((E) item);
+            Node<E> newNode = newNode((E) item);
             if (h == null)
                 h = t = newNode;
-            else
-                t.appendRelaxed(t = newNode);
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
         }
         if (h == null)
-            h = t = new Node<E>();
+            h = t = newNode(null);
         head = h;
         tail = t;
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    final class CLQSpliterator implements Spliterator<E> {
+    static final class CLQSpliterator<E> implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedQueue<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
+        CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
+            this.queue = queue;
+        }
 
         public Spliterator<E> trySplit() {
-            Node<E> p, q;
-            if ((p = current()) == null || (q = p.next) == null)
-                return null;
-            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
-            Object[] a = null;
-            do {
-                final E e;
-                if ((e = p.item) != null) {
-                    if (a == null)
-                        a = new Object[n];
-                    a[i++] = e;
+            Node<E> p;
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    if ((a[i] = p.item) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (p != null && i < n);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
                 }
-                if (p == (p = q))
-                    p = first();
-            } while (p != null && (q = p.next) != null && i < n);
-            setCurrent(p);
-            return (i == 0) ? null :
-                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
-                                                   Spliterator.NONNULL |
-                                                   Spliterator.CONCURRENT));
+            }
+            return null;
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            final Node<E> p;
-            if ((p = current()) != null) {
-                current = null;
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
                 exhausted = true;
-                forEachFrom(action, p);
+                do {
+                    E e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
             }
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
             Node<E> p;
-            if ((p = current()) != null) {
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
                 E e;
                 do {
                     e = p.item;
                     if (p == (p = p.next))
-                        p = first();
+                        p = q.first();
                 } while (e == null && p != null);
-                setCurrent(p);
+                if ((current = p) == null)
+                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -914,24 +890,11 @@
             return false;
         }
 
-        private void setCurrent(Node<E> p) {
-            if ((current = p) == null)
-                exhausted = true;
-        }
-
-        private Node<E> current() {
-            Node<E> p;
-            if ((p = current) == null && !exhausted)
-                setCurrent(p = first());
-            return p;
-        }
-
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return (Spliterator.ORDERED |
-                    Spliterator.NONNULL |
-                    Spliterator.CONCURRENT);
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
         }
     }
 
@@ -953,123 +916,36 @@
      */
     @Override
     public Spliterator<E> spliterator() {
-        return new CLQSpliterator();
+        return new CLQSpliterator<E>(this);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
+    // Unsafe mechanics
 
-    public void clear() {
-        bulkRemove(e -> true);
-    }
-
-    /**
-     * Tolerate this many consecutive dead nodes before CAS-collapsing.
-     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
-     */
-    private static final int MAX_HOPS = 8;
-
-    /** Implementation of bulk remove methods. */
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        boolean removed = false;
-        restartFromHead: for (;;) {
-            int hops = MAX_HOPS;
-            // c will be CASed to collapse intervening dead nodes between
-            // pred (or head if null) and p.
-            for (Node<E> p = head, c = p, pred = null, q; p != null; p = q) {
-                q = p.next;
-                final E item; boolean pAlive;
-                if (pAlive = ((item = p.item) != null)) {
-                    if (filter.test(item)) {
-                        if (p.casItem(item, null))
-                            removed = true;
-                        pAlive = false;
-                    }
-                }
-                if (pAlive || q == null || --hops == 0) {
-                    // p might already be self-linked here, but if so:
-                    // - CASing head will surely fail
-                    // - CASing pred's next will be useless but harmless.
-                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
-                        || pAlive) {
-                        // if CAS failed or alive, abandon old pred
-                        hops = MAX_HOPS;
-                        pred = p;
-                        c = q;
-                    }
-                } else if (p == q)
-                    continue restartFromHead;
-            }
-            return removed;
-        }
-    }
-
-    /**
-     * Runs action on each element found during a traversal starting at p.
-     * If p is null, the action is not run.
-     */
-    void forEachFrom(Consumer<? super E> action, Node<E> p) {
-        for (Node<E> pred = null; p != null; ) {
-            Node<E> q = p.next;
-            final E item;
-            if ((item = p.item) != null) {
-                action.accept(item);
-                pred = p; p = q; continue;
-            }
-            for (Node<E> c = p;; q = p.next) {
-                if (q == null || q.item != null) {
-                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                }
-                if (p == (p = q)) { pred = null; p = head; break; }
-            }
-        }
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        forEachFrom(action, head);
-    }
-
-    // VarHandle mechanics
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
-    static final VarHandle ITEM;
-    static final VarHandle NEXT;
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long ITEM;
+    private static final long NEXT;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
-                                   Node.class);
-            TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
-                                   Node.class);
-            ITEM = l.findVarHandle(Node.class, "item", Object.class);
-            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
+            ITEM = U.objectFieldOffset
+                (Node.class.getDeclaredField("item"));
+            NEXT = U.objectFieldOffset
+                (Node.class.getDeclaredField("next"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
index 2037e31..69dae6f 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -41,8 +41,14 @@
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
 /**
- * A {@link Map} providing thread safety and atomicity guarantees.
+ * A {@link java.util.Map} providing thread safety and atomicity
+ * guarantees.
  *
  * <p>To maintain the specified guarantees, default implementations of
  * methods including {@link #putIfAbsent} inherited from {@link Map}
@@ -59,10 +65,6 @@
  * actions subsequent to the access or removal of that object from
  * the {@code ConcurrentMap} in another thread.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
@@ -180,10 +182,10 @@
      *         is not supported by this map
      * @throws ClassCastException if the key or value is of an inappropriate
      *         type for this map
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified key or value is null,
      *         and this map does not permit null keys or values
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object key, Object value);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index 1666c8b..94a90cd 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -38,14 +38,14 @@
 import java.util.NavigableMap;
 import java.util.NavigableSet;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
  * and recursively so for its navigable sub-maps.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index db14d4b..583244b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.io.Serializable;
 import java.util.AbstractCollection;
 import java.util.AbstractMap;
@@ -48,6 +46,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.Set;
@@ -58,7 +57,10 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.concurrent.atomic.LongAdder;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -87,7 +89,12 @@
  * associated map using {@code put}, {@code putIfAbsent}, or
  * {@code replace}, depending on exactly which effect you need.)
  *
- * <p>Beware that bulk operations {@code putAll}, {@code equals},
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>not</em> a constant-time operation. Because of the
+ * asynchronous nature of these maps, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code putAll}, {@code equals},
  * {@code toArray}, {@code containsValue}, and {@code clear} are
  * <em>not</em> guaranteed to be performed atomically. For example, an
  * iterator operating concurrently with a {@code putAll} operation
@@ -100,10 +107,6 @@
  * null return values cannot be reliably distinguished from the absence of
  * elements.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
@@ -154,35 +157,42 @@
      * be slow and space-intensive using AtomicMarkedReference), nodes
      * use direct CAS'able next pointers.  On deletion, instead of
      * marking a pointer, they splice in another node that can be
-     * thought of as standing for a marked pointer (see method
-     * unlinkNode).  Using plain nodes acts roughly like "boxed"
-     * implementations of marked pointers, but uses new nodes only
-     * when nodes are deleted, not for every link.  This requires less
-     * space and supports faster traversal. Even if marked references
-     * were better supported by JVMs, traversal using this technique
-     * might still be faster because any search need only read ahead
-     * one more node than otherwise required (to check for trailing
-     * marker) rather than unmasking mark bits or whatever on each
-     * read.
+     * thought of as standing for a marked pointer (indicating this by
+     * using otherwise impossible field values).  Using plain nodes
+     * acts roughly like "boxed" implementations of marked pointers,
+     * but uses new nodes only when nodes are deleted, not for every
+     * link.  This requires less space and supports faster
+     * traversal. Even if marked references were better supported by
+     * JVMs, traversal using this technique might still be faster
+     * because any search need only read ahead one more node than
+     * otherwise required (to check for trailing marker) rather than
+     * unmasking mark bits or whatever on each read.
      *
      * This approach maintains the essential property needed in the HM
      * algorithm of changing the next-pointer of a deleted node so
      * that any other CAS of it will fail, but implements the idea by
-     * changing the pointer to point to a different node (with
-     * otherwise illegal null fields), not by marking it.  While it
-     * would be possible to further squeeze space by defining marker
-     * nodes not to have key/value fields, it isn't worth the extra
-     * type-testing overhead.  The deletion markers are rarely
-     * encountered during traversal, are easily detected via null
-     * checks that are needed anyway, and are normally quickly garbage
-     * collected. (Note that this technique would not work well in
-     * systems without garbage collection.)
+     * changing the pointer to point to a different node, not by
+     * marking it.  While it would be possible to further squeeze
+     * space by defining marker nodes not to have key/value fields, it
+     * isn't worth the extra type-testing overhead.  The deletion
+     * markers are rarely encountered during traversal and are
+     * normally quickly garbage collected. (Note that this technique
+     * would not work well in systems without garbage collection.)
      *
      * In addition to using deletion markers, the lists also use
      * nullness of value fields to indicate deletion, in a style
      * similar to typical lazy-deletion schemes.  If a node's value is
      * null, then it is considered logically deleted and ignored even
-     * though it is still reachable.
+     * though it is still reachable. This maintains proper control of
+     * concurrent replace vs delete operations -- an attempted replace
+     * must fail if a delete beat it by nulling field, and a delete
+     * must return the last non-null value held in the field. (Note:
+     * Null, rather than some special marker, is used for value fields
+     * here because it just so happens to mesh with the Map API
+     * requirement that method get returns null if there is no
+     * mapping, which allows nodes to remain concurrently readable
+     * even when deleted. Using any other marker value here would be
+     * messy at best.)
      *
      * Here's the sequence of events for a deletion of node n with
      * predecessor b and successor f, initially:
@@ -192,8 +202,9 @@
      *        +------+       +------+      +------+
      *
      * 1. CAS n's value field from non-null to null.
-     *    Traversals encountering a node with null value ignore it.
-     *    However, ongoing insertions and deletions might still modify
+     *    From this point on, no public operations encountering
+     *    the node consider this mapping to exist. However, other
+     *    ongoing insertions and deletions might still modify
      *    n's next pointer.
      *
      * 2. CAS n's next pointer to point to a new marker node.
@@ -216,7 +227,12 @@
      * thread noticed during a traversal a node with null value and
      * helped out by marking and/or unlinking.  This helping-out
      * ensures that no thread can become stuck waiting for progress of
-     * the deleting thread.
+     * the deleting thread.  The use of marker nodes slightly
+     * complicates helping-out code because traversals must track
+     * consistent reads of up to four nodes (b, n, marker, f), not
+     * just (b, n, f), although the next field of a marker is
+     * immutable, and once a next field is CAS'ed to point to a
+     * marker, it never again changes, so this requires less care.
      *
      * Skip lists add indexing to this scheme, so that the base-level
      * traversals start close to the locations being found, inserted
@@ -226,101 +242,113 @@
      * b) that are not (structurally) deleted, otherwise retrying
      * after processing the deletion.
      *
-     * Index levels are maintained using CAS to link and unlink
-     * successors ("right" fields).  Races are allowed in index-list
-     * operations that can (rarely) fail to link in a new index node.
-     * (We can't do this of course for data nodes.)  However, even
-     * when this happens, the index lists correctly guide search.
-     * This can impact performance, but since skip lists are
-     * probabilistic anyway, the net result is that under contention,
-     * the effective "p" value may be lower than its nominal value.
+     * Index levels are maintained as lists with volatile next fields,
+     * using CAS to link and unlink.  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node
+     * or delete one. (We can't do this of course for data nodes.)
+     * However, even when this happens, the index lists remain sorted,
+     * so correctly serve as indices.  This can impact performance,
+     * but since skip lists are probabilistic anyway, the net result
+     * is that under contention, the effective "p" value may be lower
+     * than its nominal value. And race windows are kept small enough
+     * that in practice these failures are rare, even under a lot of
+     * contention.
      *
-     * Index insertion and deletion sometimes require a separate
-     * traversal pass occurring after the base-level action, to add or
-     * remove index nodes.  This adds to single-threaded overhead, but
-     * improves contended multithreaded performance by narrowing
-     * interference windows, and allows deletion to ensure that all
-     * index nodes will be made unreachable upon return from a public
-     * remove operation, thus avoiding unwanted garbage retention.
+     * The fact that retries (for both base and index lists) are
+     * relatively cheap due to indexing allows some minor
+     * simplifications of retry logic. Traversal restarts are
+     * performed after most "helping-out" CASes. This isn't always
+     * strictly necessary, but the implicit backoffs tend to help
+     * reduce other downstream failed CAS's enough to outweigh restart
+     * cost.  This worsens the worst case, but seems to improve even
+     * highly contended cases.
+     *
+     * Unlike most skip-list implementations, index insertion and
+     * deletion here require a separate traversal pass occurring after
+     * the base-level action, to add or remove index nodes.  This adds
+     * to single-threaded overhead, but improves contended
+     * multithreaded performance by narrowing interference windows,
+     * and allows deletion to ensure that all index nodes will be made
+     * unreachable upon return from a public remove operation, thus
+     * avoiding unwanted garbage retention. This is more important
+     * here than in some other data structures because we cannot null
+     * out node fields referencing user keys since they might still be
+     * read by other ongoing traversals.
      *
      * Indexing uses skip list parameters that maintain good search
      * performance while using sparser-than-usual indices: The
-     * hardwired parameters k=1, p=0.5 (see method doPut) mean that
-     * about one-quarter of the nodes have indices. Of those that do,
-     * half have one level, a quarter have two, and so on (see Pugh's
-     * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
-     * (appropriate for up to 2^63 elements).  The expected total
-     * space requirement for a map is slightly less than for the
-     * current implementation of java.util.TreeMap.
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean
+     * that about one-quarter of the nodes have indices. Of those that
+     * do, half have one level, a quarter have two, and so on (see
+     * Pugh's Skip List Cookbook, sec 3.4).  The expected total space
+     * requirement for a map is slightly less than for the current
+     * implementation of java.util.TreeMap.
      *
      * Changing the level of the index (i.e, the height of the
-     * tree-like structure) also uses CAS.  Creation of an index with
-     * height greater than the current level adds a level to the head
-     * index by CAS'ing on a new top-most head. To maintain good
-     * performance after a lot of removals, deletion methods
-     * heuristically try to reduce the height if the topmost levels
-     * appear to be empty.  This may encounter races in which it is
-     * possible (but rare) to reduce and "lose" a level just as it is
-     * about to contain an index (that will then never be
-     * encountered). This does no structural harm, and in practice
-     * appears to be a better option than allowing unrestrained growth
-     * of levels.
+     * tree-like structure) also uses CAS. The head index has initial
+     * level/height of one. Creation of an index with height greater
+     * than the current level adds a level to the head index by
+     * CAS'ing on a new top-most head. To maintain good performance
+     * after a lot of removals, deletion methods heuristically try to
+     * reduce the height if the topmost levels appear to be empty.
+     * This may encounter races in which it possible (but rare) to
+     * reduce and "lose" a level just as it is about to contain an
+     * index (that will then never be encountered). This does no
+     * structural harm, and in practice appears to be a better option
+     * than allowing unrestrained growth of levels.
      *
-     * This class provides concurrent-reader-style memory consistency,
-     * ensuring that read-only methods report status and/or values no
-     * staler than those holding at method entry. This is done by
-     * performing all publication and structural updates using
-     * (volatile) CAS, placing an acquireFence in a few access
-     * methods, and ensuring that linked objects are transitively
-     * acquired via dependent reads (normally once) unless performing
-     * a volatile-mode CAS operation (that also acts as an acquire and
-     * release).  This form of fence-hoisting is similar to RCU and
-     * related techniques (see McKenney's online book
-     * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
-     * It minimizes overhead that may otherwise occur when using so
-     * many volatile-mode reads. Using explicit acquireFences is
-     * logistically easier than targeting particular fields to be read
-     * in acquire mode: fences are just hoisted up as far as possible,
-     * to the entry points or loop headers of a few methods. A
-     * potential disadvantage is that these few remaining fences are
-     * not easily optimized away by compilers under exclusively
-     * single-thread use.  It requires some care to avoid volatile
-     * mode reads of other fields. (Note that the memory semantics of
-     * a reference dependently read in plain mode exactly once are
-     * equivalent to those for atomic opaque mode.)  Iterators and
-     * other traversals encounter each node and value exactly once.
-     * Other operations locate an element (or position to insert an
-     * element) via a sequence of dereferences. This search is broken
-     * into two parts. Method findPredecessor (and its specialized
-     * embeddings) searches index nodes only, returning a base-level
-     * predecessor of the key. Callers carry out the base-level
-     * search, restarting if encountering a marker preventing link
-     * modification.  In some cases, it is possible to encounter a
-     * node multiple times while descending levels. For mutative
-     * operations, the reported value is validated using CAS (else
-     * retrying), preserving linearizability with respect to each
-     * other. Others may return any (non-null) value holding in the
-     * course of the method call.  (Search-based methods also include
-     * some useless-looking explicit null checks designed to allow
-     * more fields to be nulled out upon removal, to reduce floating
-     * garbage, but which is not currently done, pending discovery of
-     * a way to do this with less impact on other operations.)
+     * The code for all this is more verbose than you'd like. Most
+     * operations entail locating an element (or position to insert an
+     * element). The code to do this can't be nicely factored out
+     * because subsequent uses require a snapshot of predecessor
+     * and/or successor and/or value fields which can't be returned
+     * all at once, at least not without creating yet another object
+     * to hold them -- creating such little objects is an especially
+     * bad idea for basic internal search operations because it adds
+     * to GC overhead.  (This is one of the few times I've wished Java
+     * had macros.) Instead, some traversal code is interleaved within
+     * insertion and removal operations.  The control logic to handle
+     * all the retry conditions is sometimes twisty. Most search is
+     * broken into 2 parts. findPredecessor() searches index nodes
+     * only, returning a base-level predecessor of the key. findNode()
+     * finishes out the base-level search. Even with this factoring,
+     * there is a fair amount of near-duplication of code to handle
+     * variants.
      *
      * To produce random values without interference across threads,
      * we use within-JDK thread local random support (via the
      * "secondary seed", to avoid interference with user-level
      * ThreadLocalRandom.)
      *
+     * A previous version of this class wrapped non-comparable keys
+     * with their comparators to emulate Comparables when using
+     * comparators vs Comparables.  However, JVMs now appear to better
+     * handle infusing comparator-vs-comparable choice into search
+     * loops. Static method cpr(comparator, x, y) is used for all
+     * comparisons, which works well as long as the comparator
+     * argument is set up outside of loops (thus sometimes passed as
+     * an argument to internal methods) to avoid field re-reads.
+     *
      * For explanation of algorithms sharing at least a couple of
      * features with this one, see Mikhail Fomitchev's thesis
      * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
      * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
      * thesis (http://www.cs.chalmers.se/~phs/).
      *
+     * Given the use of tree-like index nodes, you might wonder why
+     * this doesn't use some kind of search tree instead, which would
+     * support somewhat faster search operations. The reason is that
+     * there are no known efficient lock-free insertion and deletion
+     * algorithms for search trees. The immutability of the "down"
+     * links of index nodes (as opposed to mutable "left" fields in
+     * true trees) makes this tractable using only CAS operations.
+     *
      * Notation guide for local variables
-     * Node:         b, n, f, p for  predecessor, node, successor, aux
+     * Node:         b, n, f    for  predecessor, node, successor
      * Index:        q, r, d    for index node, right, down.
+     *               t          for another index node
      * Head:         h
+     * Levels:       j
      * Keys:         k, key
      * Values:       v, value
      * Comparisons:  c
@@ -329,6 +357,16 @@
     private static final long serialVersionUID = -8627078645895051609L;
 
     /**
+     * Special value used to identify base-level header.
+     */
+    static final Object BASE_HEADER = new Object();
+
+    /**
+     * The topmost head index of the skiplist.
+     */
+    private transient volatile HeadIndex<K,V> head;
+
+    /**
      * The comparator used to maintain order in this map, or null if
      * using natural ordering.  (Non-private to simplify access in
      * nested classes.)
@@ -336,152 +374,316 @@
      */
     final Comparator<? super K> comparator;
 
-    /** Lazily initialized topmost index of the skiplist. */
-    private transient Index<K,V> head;
-    /** Lazily initialized element count */
-    private transient LongAdder adder;
     /** Lazily initialized key set */
     private transient KeySet<K,V> keySet;
-    /** Lazily initialized values collection */
-    private transient Values<K,V> values;
     /** Lazily initialized entry set */
     private transient EntrySet<K,V> entrySet;
-    /** Lazily initialized descending map */
-    private transient SubMap<K,V> descendingMap;
+    /** Lazily initialized values collection */
+    private transient Values<K,V> values;
+    /** Lazily initialized descending key set */
+    private transient ConcurrentNavigableMap<K,V> descendingMap;
+
+    /**
+     * Initializes or resets state. Needed by constructors, clone,
+     * clear, readObject. and ConcurrentSkipListSet.clone.
+     * (Note that comparator must be separately initialized.)
+     */
+    private void initialize() {
+        keySet = null;
+        entrySet = null;
+        values = null;
+        descendingMap = null;
+        head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
+                                  null, null, 1);
+    }
+
+    /**
+     * compareAndSet head node.
+     */
+    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    /* ---------------- Nodes -------------- */
 
     /**
      * Nodes hold keys and values, and are singly linked in sorted
      * order, possibly with some intervening marker nodes. The list is
-     * headed by a header node accessible as head.node. Headers and
-     * marker nodes have null keys. The val field (but currently not
-     * the key field) is nulled out upon deletion.
+     * headed by a dummy node accessible as head.node. The value field
+     * is declared only as Object because it takes special non-V
+     * values for marker and header nodes.
      */
     static final class Node<K,V> {
-        final K key; // currently, never detached
-        V val;
-        Node<K,V> next;
-        Node(K key, V value, Node<K,V> next) {
+        final K key;
+        volatile Object value;
+        volatile Node<K,V> next;
+
+        /**
+         * Creates a new regular node.
+         */
+        Node(K key, Object value, Node<K,V> next) {
             this.key = key;
-            this.val = value;
+            this.value = value;
             this.next = next;
         }
+
+        /**
+         * Creates a new marker node. A marker is distinguished by
+         * having its value field point to itself.  Marker nodes also
+         * have null keys, a fact that is exploited in a few places,
+         * but this doesn't distinguish markers from the base-level
+         * header node (head.node), which also has a null key.
+         */
+        Node(Node<K,V> next) {
+            this.key = null;
+            this.value = this;
+            this.next = next;
+        }
+
+        /**
+         * compareAndSet value field.
+         */
+        boolean casValue(Object cmp, Object val) {
+            return U.compareAndSwapObject(this, VALUE, cmp, val);
+        }
+
+        /**
+         * compareAndSet next field.
+         */
+        boolean casNext(Node<K,V> cmp, Node<K,V> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        /**
+         * Returns true if this node is a marker. This method isn't
+         * actually called in any current code checking for markers
+         * because callers will have already read value field and need
+         * to use that read (not another done here) and so directly
+         * test if value points to node.
+         *
+         * @return true if this node is a marker node
+         */
+        boolean isMarker() {
+            return value == this;
+        }
+
+        /**
+         * Returns true if this node is the header of base-level list.
+         * @return true if this node is header node
+         */
+        boolean isBaseHeader() {
+            return value == BASE_HEADER;
+        }
+
+        /**
+         * Tries to append a deletion marker to this node.
+         * @param f the assumed current successor of this node
+         * @return true if successful
+         */
+        boolean appendMarker(Node<K,V> f) {
+            return casNext(f, new Node<K,V>(f));
+        }
+
+        /**
+         * Helps out a deletion by appending marker or unlinking from
+         * predecessor. This is called during traversals when value
+         * field seen to be null.
+         * @param b predecessor
+         * @param f successor
+         */
+        void helpDelete(Node<K,V> b, Node<K,V> f) {
+            /*
+             * Rechecking links and then doing only one of the
+             * help-out stages per call tends to minimize CAS
+             * interference among helping threads.
+             */
+            if (f == next && this == b.next) {
+                if (f == null || f.value != f) // not already marked
+                    casNext(f, new Node<K,V>(f));
+                else
+                    b.casNext(this, f.next);
+            }
+        }
+
+        /**
+         * Returns value if this node contains a valid key-value pair,
+         * else null.
+         * @return this node's value if it isn't a marker or header or
+         * is deleted, else null
+         */
+        V getValidValue() {
+            Object v = value;
+            if (v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return vv;
+        }
+
+        /**
+         * Creates and returns a new SimpleImmutableEntry holding current
+         * mapping if this node holds a valid value, else null.
+         * @return new entry or null
+         */
+        AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
+            Object v = value;
+            if (v == null || v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long VALUE;
+        private static final long NEXT;
+
+        static {
+            try {
+                VALUE = U.objectFieldOffset
+                    (Node.class.getDeclaredField("value"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
     }
 
+    /* ---------------- Indexing -------------- */
+
     /**
-     * Index nodes represent the levels of the skip list.
+     * Index nodes represent the levels of the skip list.  Note that
+     * even though both Nodes and Indexes have forward-pointing
+     * fields, they have different types and are handled in different
+     * ways, that can't nicely be captured by placing field in a
+     * shared abstract class.
      */
-    static final class Index<K,V> {
-        final Node<K,V> node;  // currently, never detached
+    static class Index<K,V> {
+        final Node<K,V> node;
         final Index<K,V> down;
-        Index<K,V> right;
+        volatile Index<K,V> right;
+
+        /**
+         * Creates index node with given values.
+         */
         Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
             this.node = node;
             this.down = down;
             this.right = right;
         }
+
+        /**
+         * compareAndSet right field.
+         */
+        final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
+            return U.compareAndSwapObject(this, RIGHT, cmp, val);
+        }
+
+        /**
+         * Returns true if the node this indexes has been deleted.
+         * @return true if indexed node is known to be deleted
+         */
+        final boolean indexesDeletedNode() {
+            return node.value == null;
+        }
+
+        /**
+         * Tries to CAS newSucc as successor.  To minimize races with
+         * unlink that may lose this index node, if the node being
+         * indexed is known to be deleted, it doesn't try to link in.
+         * @param succ the expected current successor
+         * @param newSucc the new successor
+         * @return true if successful
+         */
+        final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
+            Node<K,V> n = node;
+            newSucc.right = succ;
+            return n.value != null && casRight(succ, newSucc);
+        }
+
+        /**
+         * Tries to CAS right field to skip over apparent successor
+         * succ.  Fails (forcing a retraversal by caller) if this node
+         * is known to be deleted.
+         * @param succ the expected current successor
+         * @return true if successful
+         */
+        final boolean unlink(Index<K,V> succ) {
+            return node.value != null && casRight(succ, succ.right);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long RIGHT;
+        static {
+            try {
+                RIGHT = U.objectFieldOffset
+                    (Index.class.getDeclaredField("right"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
     }
 
-    /* ----------------  Utilities -------------- */
+    /* ---------------- Head nodes -------------- */
+
+    /**
+     * Nodes heading each level keep track of their level.
+     */
+    static final class HeadIndex<K,V> extends Index<K,V> {
+        final int level;
+        HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
+            super(node, down, right);
+            this.level = level;
+        }
+    }
+
+    /* ---------------- Comparison utilities -------------- */
 
     /**
      * Compares using comparator or natural ordering if null.
      * Called only by methods that have performed required type checks.
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
-    static int cpr(Comparator c, Object x, Object y) {
+    static final int cpr(Comparator c, Object x, Object y) {
         return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
     }
 
-    /**
-     * Returns the header for base node list, or null if uninitialized
-     */
-    final Node<K,V> baseHead() {
-        Index<K,V> h;
-        VarHandle.acquireFence();
-        return ((h = head) == null) ? null : h.node;
-    }
-
-    /**
-     * Tries to unlink deleted node n from predecessor b (if both
-     * exist), by first splicing in a marker if not already present.
-     * Upon return, node n is sure to be unlinked from b, possibly
-     * via the actions of some other thread.
-     *
-     * @param b if nonnull, predecessor
-     * @param n if nonnull, node known to be deleted
-     */
-    static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
-        if (b != null && n != null) {
-            Node<K,V> f, p;
-            for (;;) {
-                if ((f = n.next) != null && f.key == null) {
-                    p = f.next;               // already marked
-                    break;
-                }
-                else if (NEXT.compareAndSet(n, f,
-                                            new Node<K,V>(null, null, f))) {
-                    p = f;                    // add marker
-                    break;
-                }
-            }
-            NEXT.compareAndSet(b, n, p);
-        }
-    }
-
-    /**
-     * Adds to element count, initializing adder if necessary
-     *
-     * @param c count to add
-     */
-    private void addCount(long c) {
-        LongAdder a;
-        do {} while ((a = adder) == null &&
-                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
-        a.add(c);
-    }
-
-    /**
-     * Returns element count, initializing adder if necessary.
-     */
-    final long getAdderCount() {
-        LongAdder a; long c;
-        do {} while ((a = adder) == null &&
-                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
-        return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
-    }
-
     /* ---------------- Traversal -------------- */
 
     /**
-     * Returns an index node with key strictly less than given key.
-     * Also unlinks indexes to deleted nodes found along the way.
-     * Callers rely on this side-effect of clearing indices to deleted
-     * nodes.
-     *
-     * @param key if nonnull the key
-     * @return a predecessor node of key, or null if uninitialized or null key
+     * Returns a base-level node with key strictly less than given key,
+     * or the base-level header if there is no such node.  Also
+     * unlinks indexes to deleted nodes found along the way.  Callers
+     * rely on this side-effect of clearing indices to deleted nodes.
+     * @param key the key
+     * @return a predecessor of key
      */
     private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
-        Index<K,V> q;
-        VarHandle.acquireFence();
-        if ((q = head) == null || key == null)
-            return null;
-        else {
-            for (Index<K,V> r, d;;) {
-                while ((r = q.right) != null) {
-                    Node<K,V> p; K k;
-                    if ((p = r.node) == null || (k = p.key) == null ||
-                        p.val == null)  // unlink index to deleted node
-                        RIGHT.compareAndSet(q, r, r.right);
-                    else if (cpr(cmp, key, k) > 0)
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        for (;;) {
+            for (Index<K,V> q = head, r = q.right, d;;) {
+                if (r != null) {
+                    Node<K,V> n = r.node;
+                    K k = n.key;
+                    if (n.value == null) {
+                        if (!q.unlink(r))
+                            break;           // restart
+                        r = q.right;         // reread r
+                        continue;
+                    }
+                    if (cpr(cmp, key, k) > 0) {
                         q = r;
-                    else
-                        break;
+                        r = r.right;
+                        continue;
+                    }
                 }
-                if ((d = q.down) != null)
-                    q = d;
-                else
+                if ((d = q.down) == null)
                     return q.node;
+                q = d;
+                r = d.right;
             }
         }
     }
@@ -491,11 +693,41 @@
      * deleted nodes seen along the way.  Repeatedly traverses at
      * base-level looking for key starting at predecessor returned
      * from findPredecessor, processing base-level deletions as
-     * encountered. Restarts occur, at traversal step encountering
-     * node n, if n's key field is null, indicating it is a marker, so
-     * its predecessor is deleted before continuing, which we help do
-     * by re-finding a valid predecessor.  The traversal loops in
-     * doPut, doRemove, and findNear all include the same checks.
+     * encountered. Some callers rely on this side-effect of clearing
+     * deleted nodes.
+     *
+     * Restarts occur, at traversal step centered on node n, if:
+     *
+     *   (1) After reading n's next field, n is no longer assumed
+     *       predecessor b's current successor, which means that
+     *       we don't have a consistent 3-node snapshot and so cannot
+     *       unlink any subsequent deleted nodes encountered.
+     *
+     *   (2) n's value field is null, indicating n is deleted, in
+     *       which case we help out an ongoing structural deletion
+     *       before retrying.  Even though there are cases where such
+     *       unlinking doesn't require restart, they aren't sorted out
+     *       here because doing so would not usually outweigh cost of
+     *       restarting.
+     *
+     *   (3) n is a marker or n's predecessor's value field is null,
+     *       indicating (among other possibilities) that
+     *       findPredecessor returned a deleted node. We can't unlink
+     *       the node because we don't know its predecessor, so rely
+     *       on another call to findPredecessor to notice and return
+     *       some earlier predecessor, which it will do. This check is
+     *       only strictly needed at beginning of loop, (and the
+     *       b.value check isn't strictly needed at all) but is done
+     *       each iteration to help avoid contention with other
+     *       threads by callers that will fail to be able to change
+     *       links, and so will retry anyway.
+     *
+     * The traversal loops in doPut, doRemove, and findNear all
+     * include the same three kinds of checks. And specialized
+     * versions appear in findFirst, and findLast and their variants.
+     * They can't easily share code because each uses the reads of
+     * fields held in locals occurring in the orders they were
+     * performed.
      *
      * @param key the key
      * @return node holding key, or null if no such
@@ -504,81 +736,67 @@
         if (key == null)
             throw new NullPointerException(); // don't postpone errors
         Comparator<? super K> cmp = comparator;
-        Node<K,V> b;
-        outer: while ((b = findPredecessor(key, cmp)) != null) {
-            for (;;) {
-                Node<K,V> n; K k; V v; int c;
-                if ((n = b.next) == null)
-                    break outer;               // empty
-                else if ((k = n.key) == null)
-                    break;                     // b is deleted
-                else if ((v = n.val) == null)
-                    unlinkNode(b, n);          // n is deleted
-                else if ((c = cpr(cmp, key, k)) > 0)
-                    b = n;
-                else if (c == 0)
-                    return n;
-                else
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
                     break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0)
+                    return n;
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
             }
         }
         return null;
     }
 
     /**
-     * Gets value for key. Same idea as findNode, except skips over
-     * deletions and markers, and returns first encountered value to
-     * avoid possibly inconsistent rereads.
+     * Gets value for key. Almost the same as findNode, but returns
+     * the found value (to avoid retries during re-reads)
      *
      * @param key the key
      * @return the value, or null if absent
      */
     private V doGet(Object key) {
-        Index<K,V> q;
-        VarHandle.acquireFence();
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        V result = null;
-        if ((q = head) != null) {
-            outer: for (Index<K,V> r, d;;) {
-                while ((r = q.right) != null) {
-                    Node<K,V> p; K k; V v; int c;
-                    if ((p = r.node) == null || (k = p.key) == null ||
-                        (v = p.val) == null)
-                        RIGHT.compareAndSet(q, r, r.right);
-                    else if ((c = cpr(cmp, key, k)) > 0)
-                        q = r;
-                    else if (c == 0) {
-                        result = v;
-                        break outer;
-                    }
-                    else
-                        break;
-                }
-                if ((d = q.down) != null)
-                    q = d;
-                else {
-                    Node<K,V> b, n;
-                    if ((b = q.node) != null) {
-                        while ((n = b.next) != null) {
-                            V v; int c;
-                            K k = n.key;
-                            if ((v = n.val) == null || k == null ||
-                                (c = cpr(cmp, key, k)) > 0)
-                                b = n;
-                            else {
-                                if (c == 0)
-                                    result = v;
-                                break;
-                            }
-                        }
-                    }
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
                     break;
                 }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    return vv;
+                }
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
             }
         }
-        return result;
+        return null;
     }
 
     /* ---------------- Insertion -------------- */
@@ -586,160 +804,126 @@
     /**
      * Main insertion method.  Adds element if not present, or
      * replaces value if present and onlyIfAbsent is false.
-     *
      * @param key the key
      * @param value the value that must be associated with key
      * @param onlyIfAbsent if should not insert if already present
      * @return the old value, or null if newly inserted
      */
     private V doPut(K key, V value, boolean onlyIfAbsent) {
+        Node<K,V> z;             // added node
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        for (;;) {
-            Index<K,V> h; Node<K,V> b;
-            VarHandle.acquireFence();
-            int levels = 0;                    // number of levels descended
-            if ((h = head) == null) {          // try to initialize
-                Node<K,V> base = new Node<K,V>(null, null, null);
-                h = new Index<K,V>(base, null, null);
-                b = (HEAD.compareAndSet(this, null, h)) ? base : null;
-            }
-            else {
-                for (Index<K,V> q = h, r, d;;) { // count while descending
-                    while ((r = q.right) != null) {
-                        Node<K,V> p; K k;
-                        if ((p = r.node) == null || (k = p.key) == null ||
-                            p.val == null)
-                            RIGHT.compareAndSet(q, r, r.right);
-                        else if (cpr(cmp, key, k) > 0)
-                            q = r;
-                        else
-                            break;
-                    }
-                    if ((d = q.down) != null) {
-                        ++levels;
-                        q = d;
-                    }
-                    else {
-                        b = q.node;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                if (n != null) {
+                    Object v; int c;
+                    Node<K,V> f = n.next;
+                    if (n != b.next)               // inconsistent read
+                        break;
+                    if ((v = n.value) == null) {   // n is deleted
+                        n.helpDelete(b, f);
                         break;
                     }
-                }
-            }
-            if (b != null) {
-                Node<K,V> z = null;              // new node, if inserted
-                for (;;) {                       // find insertion point
-                    Node<K,V> n, p; K k; V v; int c;
-                    if ((n = b.next) == null) {
-                        if (b.key == null)       // if empty, type check key now
-                            cpr(cmp, key, key);
-                        c = -1;
-                    }
-                    else if ((k = n.key) == null)
-                        break;                   // can't append; restart
-                    else if ((v = n.val) == null) {
-                        unlinkNode(b, n);
-                        c = 1;
-                    }
-                    else if ((c = cpr(cmp, key, k)) > 0)
+                    if (b.value == null || v == n) // b is deleted
+                        break;
+                    if ((c = cpr(cmp, key, n.key)) > 0) {
                         b = n;
-                    else if (c == 0 &&
-                             (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
-                        return v;
+                        n = f;
+                        continue;
+                    }
+                    if (c == 0) {
+                        if (onlyIfAbsent || n.casValue(v, value)) {
+                            @SuppressWarnings("unchecked") V vv = (V)v;
+                            return vv;
+                        }
+                        break; // restart if lost race to replace value
+                    }
+                    // else c < 0; fall through
+                }
 
-                    if (c < 0 &&
-                        NEXT.compareAndSet(b, n,
-                                           p = new Node<K,V>(key, value, n))) {
-                        z = p;
+                z = new Node<K,V>(key, value, n);
+                if (!b.casNext(n, z))
+                    break;         // restart if lost race to append to b
+                break outer;
+            }
+        }
+
+        int rnd = ThreadLocalRandom.nextSecondarySeed();
+        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
+            int level = 1, max;
+            while (((rnd >>>= 1) & 1) != 0)
+                ++level;
+            Index<K,V> idx = null;
+            HeadIndex<K,V> h = head;
+            if (level <= (max = h.level)) {
+                for (int i = 1; i <= level; ++i)
+                    idx = new Index<K,V>(z, idx, null);
+            }
+            else { // try to grow by one level
+                level = max + 1; // hold in array and later pick the one to use
+                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
+                    (Index<K,V>[])new Index<?,?>[level+1];
+                for (int i = 1; i <= level; ++i)
+                    idxs[i] = idx = new Index<K,V>(z, idx, null);
+                for (;;) {
+                    h = head;
+                    int oldLevel = h.level;
+                    if (level <= oldLevel) // lost race to add level
+                        break;
+                    HeadIndex<K,V> newh = h;
+                    Node<K,V> oldbase = h.node;
+                    for (int j = oldLevel+1; j <= level; ++j)
+                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
+                    if (casHead(h, newh)) {
+                        h = newh;
+                        idx = idxs[level = oldLevel];
                         break;
                     }
                 }
-
-                if (z != null) {
-                    int lr = ThreadLocalRandom.nextSecondarySeed();
-                    if ((lr & 0x3) == 0) {       // add indices with 1/4 prob
-                        int hr = ThreadLocalRandom.nextSecondarySeed();
-                        long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
-                        int skips = levels;      // levels to descend before add
-                        Index<K,V> x = null;
-                        for (;;) {               // create at most 62 indices
-                            x = new Index<K,V>(z, x, null);
-                            if (rnd >= 0L || --skips < 0)
+            }
+            // find insertion points and splice in
+            splice: for (int insertionLevel = level;;) {
+                int j = h.level;
+                for (Index<K,V> q = h, r = q.right, t = idx;;) {
+                    if (q == null || t == null)
+                        break splice;
+                    if (r != null) {
+                        Node<K,V> n = r.node;
+                        // compare before deletion check avoids needing recheck
+                        int c = cpr(cmp, key, n.key);
+                        if (n.value == null) {
+                            if (!q.unlink(r))
                                 break;
-                            else
-                                rnd <<= 1;
+                            r = q.right;
+                            continue;
                         }
-                        if (addIndices(h, skips, x, cmp) && skips < 0 &&
-                            head == h) {         // try to add new level
-                            Index<K,V> hx = new Index<K,V>(z, x, null);
-                            Index<K,V> nh = new Index<K,V>(h.node, h, hx);
-                            HEAD.compareAndSet(this, h, nh);
+                        if (c > 0) {
+                            q = r;
+                            r = r.right;
+                            continue;
                         }
-                        if (z.val == null)       // deleted while adding indices
-                            findPredecessor(key, cmp); // clean
                     }
-                    addCount(1L);
-                    return null;
+
+                    if (j == insertionLevel) {
+                        if (!q.link(r, t))
+                            break; // restart
+                        if (t.node.value == null) {
+                            findNode(key);
+                            break splice;
+                        }
+                        if (--insertionLevel == 0)
+                            break splice;
+                    }
+
+                    if (--j >= insertionLevel && j < level)
+                        t = t.down;
+                    q = q.down;
+                    r = q.right;
                 }
             }
         }
-    }
-
-    /**
-     * Add indices after an insertion. Descends iteratively to the
-     * highest level of insertion, then recursively, to chain index
-     * nodes to lower ones. Returns null on (staleness) failure,
-     * disabling higher-level insertions. Recursion depths are
-     * exponentially less probable.
-     *
-     * @param q starting index for current level
-     * @param skips levels to skip before inserting
-     * @param x index for this insertion
-     * @param cmp comparator
-     */
-    static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
-                                    Comparator<? super K> cmp) {
-        Node<K,V> z; K key;
-        if (x != null && (z = x.node) != null && (key = z.key) != null &&
-            q != null) {                            // hoist checks
-            boolean retrying = false;
-            for (;;) {                              // find splice point
-                Index<K,V> r, d; int c;
-                if ((r = q.right) != null) {
-                    Node<K,V> p; K k;
-                    if ((p = r.node) == null || (k = p.key) == null ||
-                        p.val == null) {
-                        RIGHT.compareAndSet(q, r, r.right);
-                        c = 0;
-                    }
-                    else if ((c = cpr(cmp, key, k)) > 0)
-                        q = r;
-                    else if (c == 0)
-                        break;                      // stale
-                }
-                else
-                    c = -1;
-
-                if (c < 0) {
-                    if ((d = q.down) != null && skips > 0) {
-                        --skips;
-                        q = d;
-                    }
-                    else if (d != null && !retrying &&
-                             !addIndices(d, 0, x.down, cmp))
-                        break;
-                    else {
-                        x.right = r;
-                        if (RIGHT.compareAndSet(q, r, x))
-                            return true;
-                        else
-                            retrying = true;         // re-find splice point
-                    }
-                }
-            }
-        }
-        return false;
+        return null;
     }
 
     /* ---------------- Deletion -------------- */
@@ -749,6 +933,15 @@
      * deletion marker, unlinks predecessor, removes associated index
      * nodes, and possibly reduces head index level.
      *
+     * Index nodes are cleared out simply by calling findPredecessor.
+     * which unlinks indexes to deleted nodes found along path to key,
+     * which will include the indexes to this node.  This is done
+     * unconditionally. We can't check beforehand whether there are
+     * index nodes because it might be the case that some or all
+     * indexes hadn't been inserted yet for this node during initial
+     * search for it, and we'd like to ensure lack of garbage
+     * retention, so must call to be sure.
+     *
      * @param key the key
      * @param value if non-null, the value that must be
      * associated with key
@@ -758,36 +951,43 @@
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        V result = null;
-        Node<K,V> b;
-        outer: while ((b = findPredecessor(key, cmp)) != null &&
-                      result == null) {
-            for (;;) {
-                Node<K,V> n; K k; V v; int c;
-                if ((n = b.next) == null)
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
                     break outer;
-                else if ((k = n.key) == null)
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
                     break;
-                else if ((v = n.val) == null)
-                    unlinkNode(b, n);
-                else if ((c = cpr(cmp, key, k)) > 0)
-                    b = n;
-                else if (c < 0)
-                    break outer;
-                else if (value != null && !value.equals(v))
-                    break outer;
-                else if (VAL.compareAndSet(n, v, null)) {
-                    result = v;
-                    unlinkNode(b, n);
-                    break; // loop to clean up
+                if ((v = n.value) == null) {        // n is deleted
+                    n.helpDelete(b, f);
+                    break;
                 }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) < 0)
+                    break outer;
+                if (c > 0) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (value != null && !value.equals(v))
+                    break outer;
+                if (!n.casValue(v, null))
+                    break;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {
+                    findPredecessor(key, cmp);      // clean index
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
             }
         }
-        if (result != null) {
-            tryReduceLevel();
-            addCount(-1L);
-        }
-        return result;
+        return null;
     }
 
     /**
@@ -811,132 +1011,77 @@
      * reduction.
      */
     private void tryReduceLevel() {
-        Index<K,V> h, d, e;
-        if ((h = head) != null && h.right == null &&
-            (d = h.down) != null && d.right == null &&
-            (e = d.down) != null && e.right == null &&
-            HEAD.compareAndSet(this, h, d) &&
-            h.right != null)   // recheck
-            HEAD.compareAndSet(this, d, h);  // try to backout
+        HeadIndex<K,V> h = head;
+        HeadIndex<K,V> d;
+        HeadIndex<K,V> e;
+        if (h.level > 3 &&
+            (d = (HeadIndex<K,V>)h.down) != null &&
+            (e = (HeadIndex<K,V>)d.down) != null &&
+            e.right == null &&
+            d.right == null &&
+            h.right == null &&
+            casHead(h, d) && // try to set
+            h.right != null) // recheck
+            casHead(d, h);   // try to backout
     }
 
     /* ---------------- Finding and removing first element -------------- */
 
     /**
-     * Gets first valid node, unlinking deleted nodes if encountered.
+     * Specialized variant of findNode to get first valid node.
      * @return first node or null if empty
      */
     final Node<K,V> findFirst() {
-        Node<K,V> b, n;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if (n.val == null)
-                    unlinkNode(b, n);
-                else
-                    return n;
-            }
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
+                return null;
+            if (n.value != null)
+                return n;
+            n.helpDelete(b, n.next);
         }
-        return null;
-    }
-
-    /**
-     * Entry snapshot version of findFirst
-     */
-    final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) == null)
-                    unlinkNode(b, n);
-                else
-                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
-            }
-        }
-        return null;
     }
 
     /**
      * Removes first entry; returns its snapshot.
      * @return null if empty, else snapshot of first entry
      */
-    private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
-                    K k = n.key;
-                    unlinkNode(b, n);
-                    if (v != null) {
-                        tryReduceLevel();
-                        findPredecessor(k, comparator); // clean index
-                        addCount(-1L);
-                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    /* ---------------- Finding and removing last element -------------- */
-
-    /**
-     * Specialized version of find to get last valid node.
-     * @return last node or null if empty
-     */
-    final Node<K,V> findLast() {
-        outer: for (;;) {
-            Index<K,V> q; Node<K,V> b;
-            VarHandle.acquireFence();
-            if ((q = head) == null)
-                break;
-            for (Index<K,V> r, d;;) {
-                while ((r = q.right) != null) {
-                    Node<K,V> p;
-                    if ((p = r.node) == null || p.val == null)
-                        RIGHT.compareAndSet(q, r, r.right);
-                    else
-                        q = r;
-                }
-                if ((d = q.down) != null)
-                    q = d;
-                else {
-                    b = q.node;
-                    break;
-                }
-            }
-            if (b != null) {
-                for (;;) {
-                    Node<K,V> n;
-                    if ((n = b.next) == null) {
-                        if (b.key == null) // empty
-                            break outer;
-                        else
-                            return b;
-                    }
-                    else if (n.key == null)
-                        break;
-                    else if (n.val == null)
-                        unlinkNode(b, n);
-                    else
-                        b = n;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Entry version of findLast
-     * @return Entry for last node or null if empty
-     */
-    final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
-        for (;;) {
-            Node<K,V> n; V v;
-            if ((n = findLast()) == null)
+    private Map.Entry<K,V> doRemoveFirstEntry() {
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
                 return null;
-            if ((v = n.val) != null)
-                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            Node<K,V> f = n.next;
+            if (n != b.next)
+                continue;
+            Object v = n.value;
+            if (v == null) {
+                n.helpDelete(b, f);
+                continue;
+            }
+            if (!n.casValue(v, null))
+                continue;
+            if (!n.appendMarker(f) || !b.casNext(n, f))
+                findFirst(); // retry
+            clearIndexToFirst();
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
+        }
+    }
+
+    /**
+     * Clears out index nodes associated with deleted first entry.
+     */
+    private void clearIndexToFirst() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> r = q.right;
+                if (r != null && r.indexesDeletedNode() && !q.unlink(r))
+                    break;
+                if ((q = q.down) == null) {
+                    if (head.right == null)
+                        tryReduceLevel();
+                    return;
+                }
+            }
         }
     }
 
@@ -946,54 +1091,121 @@
      * @return null if empty, else snapshot of last entry
      */
     private Map.Entry<K,V> doRemoveLastEntry() {
-        outer: for (;;) {
-            Index<K,V> q; Node<K,V> b;
-            VarHandle.acquireFence();
-            if ((q = head) == null)
-                break;
+        for (;;) {
+            Node<K,V> b = findPredecessorOfLast();
+            Node<K,V> n = b.next;
+            if (n == null) {
+                if (b.isBaseHeader())               // empty
+                    return null;
+                else
+                    continue; // all b's successors are deleted; retry
+            }
             for (;;) {
-                Index<K,V> d, r; Node<K,V> p;
-                while ((r = q.right) != null) {
-                    if ((p = r.node) == null || p.val == null)
-                        RIGHT.compareAndSet(q, r, r.right);
-                    else if (p.next != null)
-                        q = r;  // continue only if a successor
-                    else
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
+                    break;
+                Object v = n.value;
+                if (v == null) {                    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if (f != null) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (!n.casValue(v, null))
+                    break;
+                K key = n.key;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {                              // clean index
+                    findPredecessor(key, comparator);
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+            }
+        }
+    }
+
+    /* ---------------- Finding and removing last element -------------- */
+
+    /**
+     * Specialized version of find to get last valid node.
+     * @return last node or null if empty
+     */
+    final Node<K,V> findLast() {
+        /*
+         * findPredecessor can't be used to traverse index level
+         * because this doesn't use comparisons.  So traversals of
+         * both levels are folded together.
+         */
+        Index<K,V> q = head;
+        for (;;) {
+            Index<K,V> d, r;
+            if ((r = q.right) != null) {
+                if (r.indexesDeletedNode()) {
+                    q.unlink(r);
+                    q = head; // restart
+                }
+                else
+                    q = r;
+            } else if ((d = q.down) != null) {
+                q = d;
+            } else {
+                for (Node<K,V> b = q.node, n = b.next;;) {
+                    if (n == null)
+                        return b.isBaseHeader() ? null : b;
+                    Node<K,V> f = n.next;            // inconsistent read
+                    if (n != b.next)
                         break;
+                    Object v = n.value;
+                    if (v == null) {                 // n is deleted
+                        n.helpDelete(b, f);
+                        break;
+                    }
+                    if (b.value == null || v == n)      // b is deleted
+                        break;
+                    b = n;
+                    n = f;
+                }
+                q = head; // restart
+            }
+        }
+    }
+
+    /**
+     * Specialized variant of findPredecessor to get predecessor of last
+     * valid node.  Needed when removing the last entry.  It is possible
+     * that all successors of returned node will have been deleted upon
+     * return, in which case this method can be retried.
+     * @return likely predecessor of last node
+     */
+    private Node<K,V> findPredecessorOfLast() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> d, r;
+                if ((r = q.right) != null) {
+                    if (r.indexesDeletedNode()) {
+                        q.unlink(r);
+                        break;    // must restart
+                    }
+                    // proceed as far across as possible without overshooting
+                    if (r.node.next != null) {
+                        q = r;
+                        continue;
+                    }
                 }
                 if ((d = q.down) != null)
                     q = d;
-                else {
-                    b = q.node;
-                    break;
-                }
-            }
-            if (b != null) {
-                for (;;) {
-                    Node<K,V> n; K k; V v;
-                    if ((n = b.next) == null) {
-                        if (b.key == null) // empty
-                            break outer;
-                        else
-                            break; // retry
-                    }
-                    else if ((k = n.key) == null)
-                        break;
-                    else if ((v = n.val) == null)
-                        unlinkNode(b, n);
-                    else if (n.next != null)
-                        b = n;
-                    else if (VAL.compareAndSet(n, v, null)) {
-                        unlinkNode(b, n);
-                        tryReduceLevel();
-                        findPredecessor(k, comparator); // clean index
-                        addCount(-1L);
-                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
-                    }
-                }
+                else
+                    return q.node;
             }
         }
-        return null;
     }
 
     /* ---------------- Relational operations -------------- */
@@ -1013,52 +1225,47 @@
     final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
         if (key == null)
             throw new NullPointerException();
-        Node<K,V> result;
-        outer: for (Node<K,V> b;;) {
-            if ((b = findPredecessor(key, cmp)) == null) {
-                result = null;
-                break;                   // empty
-            }
-            for (;;) {
-                Node<K,V> n; K k; int c;
-                if ((n = b.next) == null) {
-                    result = ((rel & LT) != 0 && b.key != null) ? b : null;
-                    break outer;
-                }
-                else if ((k = n.key) == null)
+        for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v;
+                if (n == null)
+                    return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
+                Node<K,V> f = n.next;
+                if (n != b.next)                  // inconsistent read
                     break;
-                else if (n.val == null)
-                    unlinkNode(b, n);
-                else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
-                         (c < 0 && (rel & LT) == 0)) {
-                    result = n;
-                    break outer;
+                if ((v = n.value) == null) {      // n is deleted
+                    n.helpDelete(b, f);
+                    break;
                 }
-                else if (c <= 0 && (rel & LT) != 0) {
-                    result = (b.key != null) ? b : null;
-                    break outer;
-                }
-                else
-                    b = n;
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                int c = cpr(cmp, key, n.key);
+                if ((c == 0 && (rel & EQ) != 0) ||
+                    (c <  0 && (rel & LT) == 0))
+                    return n;
+                if ( c <= 0 && (rel & LT) != 0)
+                    return b.isBaseHeader() ? null : b;
+                b = n;
+                n = f;
             }
         }
-        return result;
     }
 
     /**
-     * Variant of findNear returning SimpleImmutableEntry
+     * Returns SimpleImmutableEntry for results of findNear.
      * @param key the key
      * @param rel the relation -- OR'ed combination of EQ, LT, GT
      * @return Entry fitting relation, or null if no such
      */
-    final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
-                                                              Comparator<? super K> cmp) {
+    final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
+        Comparator<? super K> cmp = comparator;
         for (;;) {
-            Node<K,V> n; V v;
-            if ((n = findNear(key, rel, cmp)) == null)
+            Node<K,V> n = findNear(key, rel, cmp);
+            if (n == null)
                 return null;
-            if ((v = n.val) != null)
-                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
         }
     }
 
@@ -1070,6 +1277,7 @@
      */
     public ConcurrentSkipListMap() {
         this.comparator = null;
+        initialize();
     }
 
     /**
@@ -1082,6 +1290,7 @@
      */
     public ConcurrentSkipListMap(Comparator<? super K> comparator) {
         this.comparator = comparator;
+        initialize();
     }
 
     /**
@@ -1097,6 +1306,7 @@
      */
     public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
         this.comparator = null;
+        initialize();
         putAll(m);
     }
 
@@ -1111,7 +1321,8 @@
      */
     public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
         this.comparator = m.comparator();
-        buildFromSorted(m); // initializes transients
+        initialize();
+        buildFromSorted(m);
     }
 
     /**
@@ -1125,10 +1336,7 @@
             @SuppressWarnings("unchecked")
             ConcurrentSkipListMap<K,V> clone =
                 (ConcurrentSkipListMap<K,V>) super.clone();
-            clone.keySet = null;
-            clone.entrySet = null;
-            clone.values = null;
-            clone.descendingMap = null;
+            clone.initialize();
             clone.buildFromSorted(this);
             return clone;
         } catch (CloneNotSupportedException e) {
@@ -1144,49 +1352,58 @@
     private void buildFromSorted(SortedMap<K, ? extends V> map) {
         if (map == null)
             throw new NullPointerException();
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+
+        // Track the current rightmost node at each level. Uses an
+        // ArrayList to avoid committing to initial or maximum level.
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+
+        // initialize
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
+
         Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
             map.entrySet().iterator();
-
-        /*
-         * Add equally spaced indices at log intervals, using the bits
-         * of count during insertion. The maximum possible resulting
-         * level is less than the number of bits in a long (64). The
-         * preds array tracks the current rightmost node at each
-         * level.
-         */
-        @SuppressWarnings("unchecked")
-        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
-        Node<K,V> bp = new Node<K,V>(null, null, null);
-        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
-        long count = 0;
-
         while (it.hasNext()) {
             Map.Entry<? extends K, ? extends V> e = it.next();
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
+                do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
             K k = e.getKey();
             V v = e.getValue();
             if (k == null || v == null)
                 throw new NullPointerException();
             Node<K,V> z = new Node<K,V>(k, v, null);
-            bp = bp.next = z;
-            if ((++count & 3L) == 0L) {
-                long m = count >>> 2;
-                int i = 0;
-                Index<K,V> idx = null, q;
-                do {
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
                     idx = new Index<K,V>(z, idx, null);
-                    if ((q = preds[i]) == null)
-                        preds[i] = h = new Index<K,V>(h.node, h, idx);
-                    else
-                        preds[i] = q.right = idx;
-                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
             }
         }
-        if (count != 0L) {
-            VarHandle.releaseFence(); // emulate volatile stores
-            addCount(count);
-            head = h;
-            VarHandle.fullFence();
-        }
+        head = h;
     }
 
     /* ---------------- Serialization -------------- */
@@ -1208,14 +1425,11 @@
         s.defaultWriteObject();
 
         // Write out keys and values (alternating)
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) != null) {
-                    s.writeObject(n.key);
-                    s.writeObject(v);
-                }
-                b = n;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null) {
+                s.writeObject(n.key);
+                s.writeObject(v);
             }
         }
         s.writeObject(null);
@@ -1233,47 +1447,64 @@
         throws java.io.IOException, ClassNotFoundException {
         // Read in the Comparator and any hidden stuff
         s.defaultReadObject();
+        // Reset transients
+        initialize();
 
-        // Same idea as buildFromSorted
-        @SuppressWarnings("unchecked")
-        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
-        Node<K,V> bp = new Node<K,V>(null, null, null);
-        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
-        Comparator<? super K> cmp = comparator;
-        K prevKey = null;
-        long count = 0;
+        /*
+         * This is nearly identical to buildFromSorted, but is
+         * distinct because readObject calls can't be nicely adapted
+         * as the kind of iterator needed by buildFromSorted. (They
+         * can be, but doing so requires type cheats and/or creation
+         * of adapter classes.) It is simpler to just adapt the code.
+         */
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
 
         for (;;) {
-            K k = (K)s.readObject();
+            Object k = s.readObject();
             if (k == null)
                 break;
-            V v = (V)s.readObject();
+            Object v = s.readObject();
             if (v == null)
                 throw new NullPointerException();
-            if (prevKey != null && cpr(cmp, prevKey, k) > 0)
-                throw new IllegalStateException("out of order");
-            prevKey = k;
-            Node<K,V> z = new Node<K,V>(k, v, null);
-            bp = bp.next = z;
-            if ((++count & 3L) == 0L) {
-                long m = count >>> 2;
-                int i = 0;
-                Index<K,V> idx = null, q;
+            K key = (K) k;
+            V val = (V) v;
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
                 do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
+            Node<K,V> z = new Node<K,V>(key, val, null);
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
                     idx = new Index<K,V>(z, idx, null);
-                    if ((q = preds[i]) == null)
-                        preds[i] = h = new Index<K,V>(h.node, h, idx);
-                    else
-                        preds[i] = q.right = idx;
-                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
             }
         }
-        if (count != 0L) {
-            VarHandle.releaseFence();
-            addCount(count);
-            head = h;
-            VarHandle.fullFence();
-        }
+        head = h;
     }
 
     /* ------ Map API methods ------ */
@@ -1374,30 +1605,42 @@
     public boolean containsValue(Object value) {
         if (value == null)
             throw new NullPointerException();
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) != null && value.equals(v))
-                    return true;
-                else
-                    b = n;
-            }
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null && value.equals(v))
+                return true;
         }
         return false;
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the number of key-value mappings in this map.  If this map
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these maps, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this map
      */
     public int size() {
-        long c;
-        return ((baseHead() == null) ? 0 :
-                ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
-                Integer.MAX_VALUE : (int) c);
+        long count = 0;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if (n.getValidValue() != null)
+                ++count;
+        }
+        return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
     }
 
     /**
-     * {@inheritDoc}
+     * Returns {@code true} if this map contains no key-value mappings.
+     * @return {@code true} if this map contains no key-value mappings
      */
     public boolean isEmpty() {
         return findFirst() == null;
@@ -1407,33 +1650,7 @@
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        Index<K,V> h, r, d; Node<K,V> b;
-        VarHandle.acquireFence();
-        while ((h = head) != null) {
-            if ((r = h.right) != null)        // remove indices
-                RIGHT.compareAndSet(h, r, null);
-            else if ((d = h.down) != null)    // remove levels
-                HEAD.compareAndSet(this, h, d);
-            else {
-                long count = 0L;
-                if ((b = h.node) != null) {    // remove nodes
-                    Node<K,V> n; V v;
-                    while ((n = b.next) != null) {
-                        if ((v = n.val) != null &&
-                            VAL.compareAndSet(n, v, null)) {
-                            --count;
-                            v = null;
-                        }
-                        if (v == null)
-                            unlinkNode(b, n);
-                    }
-                }
-                if (count != 0L)
-                    addCount(count);
-                else
-                    break;
-            }
-        }
+        initialize();
     }
 
     /**
@@ -1479,15 +1696,16 @@
                               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
-        Node<K,V> n; V v;
+        Node<K,V> n; Object v;
         while ((n = findNode(key)) != null) {
-            if ((v = n.val) != null) {
-                V r = remappingFunction.apply(key, v);
+            if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                V r = remappingFunction.apply(key, vv);
                 if (r != null) {
-                    if (VAL.compareAndSet(n, v, r))
+                    if (n.casValue(vv, r))
                         return r;
                 }
-                else if (doRemove(key, v) != null)
+                else if (doRemove(key, vv) != null)
                     break;
             }
         }
@@ -1512,19 +1730,20 @@
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; V v; V r;
+            Node<K,V> n; Object v; V r;
             if ((n = findNode(key)) == null) {
                 if ((r = remappingFunction.apply(key, null)) == null)
                     break;
                 if (doPut(key, r, true) == null)
                     return r;
             }
-            else if ((v = n.val) != null) {
-                if ((r = remappingFunction.apply(key, v)) != null) {
-                    if (VAL.compareAndSet(n, v, r))
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(key, vv)) != null) {
+                    if (n.casValue(vv, r))
                         return r;
                 }
-                else if (doRemove(key, v) != null)
+                else if (doRemove(key, vv) != null)
                     break;
             }
         }
@@ -1551,17 +1770,18 @@
         if (key == null || value == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; V v; V r;
+            Node<K,V> n; Object v; V r;
             if ((n = findNode(key)) == null) {
                 if (doPut(key, value, true) == null)
                     return value;
             }
-            else if ((v = n.val) != null) {
-                if ((r = remappingFunction.apply(v, value)) != null) {
-                    if (VAL.compareAndSet(n, v, r))
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(vv, value)) != null) {
+                    if (n.casValue(vv, r))
                         return r;
                 }
-                else if (doRemove(key, v) != null)
+                else if (doRemove(key, vv) != null)
                     return null;
             }
         }
@@ -1585,11 +1805,9 @@
      * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
      * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
      * {@link Spliterator#ORDERED}, with an encounter order that is ascending
-     * key order.
-     *
-     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
-     * is {@code null} if the {@linkplain #comparator() map's comparator}
-     * is {@code null}.
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the map's comparator (see {@link #comparator()}) is {@code null}.
      * Otherwise, the spliterator's comparator is the same as or imposes the
      * same total ordering as the map's comparator.
      *
@@ -1609,15 +1827,13 @@
      * @return a navigable set view of the keys in this map
      */
     public NavigableSet<K> keySet() {
-        KeySet<K,V> ks;
-        if ((ks = keySet) != null) return ks;
-        return keySet = new KeySet<>(this);
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
     }
 
     public NavigableSet<K> navigableKeySet() {
-        KeySet<K,V> ks;
-        if ((ks = keySet) != null) return ks;
-        return keySet = new KeySet<>(this);
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
     }
 
     /**
@@ -1640,9 +1856,8 @@
      * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
      */
     public Collection<V> values() {
-        Values<K,V> vs;
-        if ((vs = values) != null) return vs;
-        return values = new Values<>(this);
+        Values<K,V> vs = values;
+        return (vs != null) ? vs : (values = new Values<>(this));
     }
 
     /**
@@ -1673,16 +1888,14 @@
      *         sorted in ascending key order
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        EntrySet<K,V> es;
-        if ((es = entrySet) != null) return es;
-        return entrySet = new EntrySet<K,V>(this);
+        EntrySet<K,V> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
     }
 
     public ConcurrentNavigableMap<K,V> descendingMap() {
-        ConcurrentNavigableMap<K,V> dm;
-        if ((dm = descendingMap) != null) return dm;
-        return descendingMap =
-            new SubMap<K,V>(this, null, false, null, false, true);
+        ConcurrentNavigableMap<K,V> dm = descendingMap;
+        return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
+                                    (this, null, false, null, false, true));
     }
 
     public NavigableSet<K> descendingKeySet() {
@@ -1710,61 +1923,19 @@
             return false;
         Map<?,?> m = (Map<?,?>) o;
         try {
-            Comparator<? super K> cmp = comparator;
-            @SuppressWarnings("unchecked")
-            Iterator<Map.Entry<?,?>> it =
-                (Iterator<Map.Entry<?,?>>)m.entrySet().iterator();
-            if (m instanceof SortedMap &&
-                ((SortedMap<?,?>)m).comparator() == cmp) {
-                Node<K,V> b, n;
-                if ((b = baseHead()) != null) {
-                    while ((n = b.next) != null) {
-                        K k; V v;
-                        if ((v = n.val) != null && (k = n.key) != null) {
-                            if (!it.hasNext())
-                                return false;
-                            Map.Entry<?,?> e = it.next();
-                            Object mk = e.getKey();
-                            Object mv = e.getValue();
-                            if (mk == null || mv == null)
-                                return false;
-                            try {
-                                if (cpr(cmp, k, mk) != 0)
-                                    return false;
-                            } catch (ClassCastException cce) {
-                                return false;
-                            }
-                            if (!mv.equals(v))
-                                return false;
-                        }
-                        b = n;
-                    }
-                }
-                return !it.hasNext();
+            for (Map.Entry<K,V> e : this.entrySet())
+                if (! e.getValue().equals(m.get(e.getKey())))
+                    return false;
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object k = e.getKey();
+                Object v = e.getValue();
+                if (k == null || v == null || !v.equals(get(k)))
+                    return false;
             }
-            else {
-                while (it.hasNext()) {
-                    V v;
-                    Map.Entry<?,?> e = it.next();
-                    Object mk = e.getKey();
-                    Object mv = e.getValue();
-                    if (mk == null || mv == null ||
-                        (v = get(mk)) == null || !v.equals(mv))
-                        return false;
-                }
-                Node<K,V> b, n;
-                if ((b = baseHead()) != null) {
-                    K k; V v; Object mv;
-                    while ((n = b.next) != null) {
-                        if ((v = n.val) != null && (k = n.key) != null &&
-                            ((mv = m.get(k)) == null || !mv.equals(v)))
-                            return false;
-                        b = n;
-                    }
-                }
-                return true;
-            }
-        } catch (ClassCastException | NullPointerException unused) {
+            return true;
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
             return false;
         }
     }
@@ -1810,13 +1981,13 @@
         if (key == null || oldValue == null || newValue == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; V v;
+            Node<K,V> n; Object v;
             if ((n = findNode(key)) == null)
                 return false;
-            if ((v = n.val) != null) {
+            if ((v = n.value) != null) {
                 if (!oldValue.equals(v))
                     return false;
-                if (VAL.compareAndSet(n, v, newValue))
+                if (n.casValue(v, newValue))
                     return true;
             }
         }
@@ -1835,11 +2006,13 @@
         if (key == null || value == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; V v;
+            Node<K,V> n; Object v;
             if ((n = findNode(key)) == null)
                 return null;
-            if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
-                return v;
+            if ((v = n.value) != null && n.casValue(v, value)) {
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
+            }
         }
     }
 
@@ -1949,7 +2122,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> lowerEntry(K key) {
-        return findNearEntry(key, LT, comparator);
+        return getNear(key, LT);
     }
 
     /**
@@ -1972,7 +2145,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> floorEntry(K key) {
-        return findNearEntry(key, LT|EQ, comparator);
+        return getNear(key, LT|EQ);
     }
 
     /**
@@ -1995,7 +2168,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> ceilingEntry(K key) {
-        return findNearEntry(key, GT|EQ, comparator);
+        return getNear(key, GT|EQ);
     }
 
     /**
@@ -2018,7 +2191,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> higherEntry(K key) {
-        return findNearEntry(key, GT, comparator);
+        return getNear(key, GT);
     }
 
     /**
@@ -2038,7 +2211,14 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> firstEntry() {
-        return findFirstEntry();
+        for (;;) {
+            Node<K,V> n = findFirst();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
     }
 
     /**
@@ -2048,7 +2228,14 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> lastEntry() {
-        return findLastEntry();
+        for (;;) {
+            Node<K,V> n = findLast();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
     }
 
     /**
@@ -2071,10 +2258,11 @@
         return doRemoveLastEntry();
     }
 
+
     /* ---------------- Iterators -------------- */
 
     /**
-     * Base of iterator classes
+     * Base of iterator classes:
      */
     abstract class Iter<T> implements Iterator<T> {
         /** the last node returned by next() */
@@ -2086,7 +2274,14 @@
 
         /** Initializes ascending iterator for entire range. */
         Iter() {
-            advance(baseHead());
+            while ((next = findFirst()) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
+            }
         }
 
         public final boolean hasNext() {
@@ -2094,58 +2289,54 @@
         }
 
         /** Advances next to higher entry. */
-        final void advance(Node<K,V> b) {
-            Node<K,V> n = null;
-            V v = null;
-            if ((lastReturned = b) != null) {
-                while ((n = b.next) != null && (v = n.val) == null)
-                    b = n;
+        final void advance() {
+            if (next == null)
+                throw new NoSuchElementException();
+            lastReturned = next;
+            while ((next = next.next) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
             }
-            nextValue = v;
-            next = n;
         }
 
-        public final void remove() {
-            Node<K,V> n; K k;
-            if ((n = lastReturned) == null || (k = n.key) == null)
+        public void remove() {
+            Node<K,V> l = lastReturned;
+            if (l == null)
                 throw new IllegalStateException();
             // It would not be worth all of the overhead to directly
             // unlink from here. Using remove is fast enough.
-            ConcurrentSkipListMap.this.remove(k);
+            ConcurrentSkipListMap.this.remove(l.key);
             lastReturned = null;
         }
+
     }
 
     final class ValueIterator extends Iter<V> {
         public V next() {
-            V v;
-            if ((v = nextValue) == null)
-                throw new NoSuchElementException();
-            advance(next);
+            V v = nextValue;
+            advance();
             return v;
         }
     }
 
     final class KeyIterator extends Iter<K> {
         public K next() {
-            Node<K,V> n;
-            if ((n = next) == null)
-                throw new NoSuchElementException();
-            K k = n.key;
-            advance(n);
-            return k;
+            Node<K,V> n = next;
+            advance();
+            return n.key;
         }
     }
 
     final class EntryIterator extends Iter<Map.Entry<K,V>> {
         public Map.Entry<K,V> next() {
-            Node<K,V> n;
-            if ((n = next) == null)
-                throw new NoSuchElementException();
-            K k = n.key;
+            Node<K,V> n = next;
             V v = nextValue;
-            advance(n);
-            return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            advance();
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
         }
     }
 
@@ -2202,7 +2393,9 @@
             Collection<?> c = (Collection<?>) o;
             try {
                 return containsAll(c) && c.containsAll(this);
-            } catch (ClassCastException | NullPointerException unused) {
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
                 return false;
             }
         }
@@ -2327,7 +2520,9 @@
             Collection<?> c = (Collection<?>) o;
             try {
                 return containsAll(c) && c.containsAll(this);
-            } catch (ClassCastException | NullPointerException unused) {
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
                 return false;
             }
         }
@@ -2369,7 +2564,7 @@
      * @serial include
      */
     static final class SubMap<K,V> extends AbstractMap<K,V>
-        implements ConcurrentNavigableMap<K,V>, Serializable {
+        implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
         private static final long serialVersionUID = -7647078645895051609L;
 
         /** Underlying map */
@@ -2387,8 +2582,8 @@
 
         // Lazily initialized view holders
         private transient KeySet<K,V> keySetView;
-        private transient Values<K,V> valuesView;
-        private transient EntrySet<K,V> entrySetView;
+        private transient Set<Map.Entry<K,V>> entrySetView;
+        private transient Collection<V> valuesView;
 
         /**
          * Creates a new submap, initializing all fields.
@@ -2447,7 +2642,9 @@
             if (k == null) // pass by markers and headers
                 return true;
             int c = cpr(cmp, k, hi);
-            return c < 0 || (c == 0 && hiInclusive);
+            if (c > 0 || (c == 0 && !hiInclusive))
+                return false;
+            return true;
         }
 
         /**
@@ -2505,34 +2702,38 @@
         Map.Entry<K,V> lowestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n; V v;
-                if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
+                ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                if (!isBeforeEnd(n, cmp))
                     return null;
-                else if ((v = n.val) != null)
-                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
             }
         }
 
         Map.Entry<K,V> highestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n; V v;
-                if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
+                ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                if (n == null || !inBounds(n.key, cmp))
                     return null;
-                else if ((v = n.val) != null)
-                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
             }
         }
 
         Map.Entry<K,V> removeLowest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
-                if ((n = loNode(cmp)) == null)
+                Node<K,V> n = loNode(cmp);
+                if (n == null)
                     return null;
-                else if (!inBounds((k = n.key), cmp))
+                K k = n.key;
+                if (!inBounds(k, cmp))
                     return null;
-                else if ((v = m.doRemove(k, null)) != null)
+                V v = m.doRemove(k, null);
+                if (v != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
@@ -2540,18 +2741,20 @@
         Map.Entry<K,V> removeHighest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
-                if ((n = hiNode(cmp)) == null)
+                Node<K,V> n = hiNode(cmp);
+                if (n == null)
                     return null;
-                else if (!inBounds((k = n.key), cmp))
+                K k = n.key;
+                if (!inBounds(k, cmp))
                     return null;
-                else if ((v = m.doRemove(k, null)) != null)
+                V v = m.doRemove(k, null);
+                if (v != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
 
         /**
-         * Submap version of ConcurrentSkipListMap.findNearEntry.
+         * Submap version of ConcurrentSkipListMap.getNearEntry.
          */
         Map.Entry<K,V> getNearEntry(K key, int rel) {
             Comparator<? super K> cmp = m.comparator;
@@ -2565,12 +2768,15 @@
                 return ((rel & LT) != 0) ? null : lowestEntry();
             if (tooHigh(key, cmp))
                 return ((rel & LT) != 0) ? highestEntry() : null;
-            AbstractMap.SimpleImmutableEntry<K,V> e =
-                m.findNearEntry(key, rel, cmp);
-            if (e == null || !inBounds(e.getKey(), cmp))
-                return null;
-            else
-                return e;
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
         }
 
         // Almost the same as getNearEntry, except for keys
@@ -2605,8 +2811,10 @@
                 Node<K,V> n = m.findNear(key, rel, cmp);
                 if (n == null || !inBounds(n.key, cmp))
                     return null;
-                if (n.val != null)
-                    return n.key;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return k;
             }
         }
 
@@ -2637,7 +2845,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.val != null)
+                if (n.getValidValue() != null)
                     ++count;
             }
             return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
@@ -2655,7 +2863,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                V v = n.val;
+                V v = n.getValidValue();
                 if (v != null && value.equals(v))
                     return true;
             }
@@ -2667,7 +2875,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.val != null)
+                if (n.getValidValue() != null)
                     m.remove(n.key);
             }
         }
@@ -2841,27 +3049,23 @@
         /* ---------------- Submap Views -------------- */
 
         public NavigableSet<K> keySet() {
-            KeySet<K,V> ks;
-            if ((ks = keySetView) != null) return ks;
-            return keySetView = new KeySet<>(this);
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
         }
 
         public NavigableSet<K> navigableKeySet() {
-            KeySet<K,V> ks;
-            if ((ks = keySetView) != null) return ks;
-            return keySetView = new KeySet<>(this);
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
         }
 
         public Collection<V> values() {
-            Values<K,V> vs;
-            if ((vs = valuesView) != null) return vs;
-            return valuesView = new Values<>(this);
+            Collection<V> vs = valuesView;
+            return (vs != null) ? vs : (valuesView = new Values<>(this));
         }
 
         public Set<Map.Entry<K,V>> entrySet() {
-            EntrySet<K,V> es;
-            if ((es = entrySetView) != null) return es;
-            return entrySetView = new EntrySet<K,V>(this);
+            Set<Map.Entry<K,V>> es = entrySetView;
+            return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
         }
 
         public NavigableSet<K> descendingKeySet() {
@@ -2881,18 +3085,19 @@
             V nextValue;
 
             SubMapIter() {
-                VarHandle.acquireFence();
                 Comparator<? super K> cmp = m.comparator;
                 for (;;) {
                     next = isDescending ? hiNode(cmp) : loNode(cmp);
                     if (next == null)
                         break;
-                    V x = next.val;
-                    if (x != null) {
+                    Object x = next.value;
+                    if (x != null && x != next) {
                         if (! inBounds(next.key, cmp))
                             next = null;
-                        else
-                            nextValue = x;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
                         break;
                     }
                 }
@@ -2918,12 +3123,14 @@
                     next = next.next;
                     if (next == null)
                         break;
-                    V x = next.val;
-                    if (x != null) {
+                    Object x = next.value;
+                    if (x != null && x != next) {
                         if (tooHigh(next.key, cmp))
                             next = null;
-                        else
-                            nextValue = x;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
                         break;
                     }
                 }
@@ -2935,12 +3142,14 @@
                     next = m.findNear(lastReturned.key, LT, cmp);
                     if (next == null)
                         break;
-                    V x = next.val;
-                    if (x != null) {
+                    Object x = next.value;
+                    if (x != null && x != next) {
                         if (tooLow(next.key, cmp))
                             next = null;
-                        else
-                            nextValue = x;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
                         break;
                     }
                 }
@@ -3020,28 +3229,22 @@
 
     public void forEach(BiConsumer<? super K, ? super V> action) {
         if (action == null) throw new NullPointerException();
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) != null)
-                    action.accept(n.key, v);
-                b = n;
-            }
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if ((v = n.getValidValue()) != null)
+                action.accept(n.key, v);
         }
     }
 
     public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
         if (function == null) throw new NullPointerException();
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                while ((v = n.val) != null) {
-                    V r = function.apply(n.key, v);
-                    if (r == null) throw new NullPointerException();
-                    if (VAL.compareAndSet(n, v, r))
-                        break;
-                }
-                b = n;
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            while ((v = n.getValidValue()) != null) {
+                V r = function.apply(n.key, v);
+                if (r == null) throw new NullPointerException();
+                if (n.casValue(v, r))
+                    break;
             }
         }
     }
@@ -3052,16 +3255,13 @@
     boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) != null) {
-                    K k = n.key;
-                    Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
-                    if (function.test(e) && remove(k, v))
-                        removed = true;
-                }
-                b = n;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && remove(k, v))
+                    removed = true;
             }
         }
         return removed;
@@ -3073,12 +3273,12 @@
     boolean removeValueIf(Predicate<? super V> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        Node<K,V> b, n; V v;
-        if ((b = baseHead()) != null) {
-            while ((n = b.next) != null) {
-                if ((v = n.val) != null && function.test(v) && remove(n.key, v))
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                if (function.test(v) && remove(k, v))
                     removed = true;
-                b = n;
             }
         }
         return removed;
@@ -3096,27 +3296,30 @@
      * off, or the end of row is encountered. Control of the number of
      * splits relies on some statistical estimation: The expected
      * remaining number of elements of a skip list when advancing
-     * either across or down decreases by about 25%.
+     * either across or down decreases by about 25%. To make this
+     * observation useful, we need to know initial size, which we
+     * don't. But we can just use Integer.MAX_VALUE so that we
+     * don't prematurely zero out while splitting.
      */
     abstract static class CSLMSpliterator<K,V> {
         final Comparator<? super K> comparator;
         final K fence;     // exclusive upper bound for keys, or null if to end
         Index<K,V> row;    // the level to split out
         Node<K,V> current; // current traversal node; initialize at origin
-        long est;          // size estimate
+        int est;           // pseudo-size estimate
         CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                        Node<K,V> origin, K fence, long est) {
+                        Node<K,V> origin, K fence, int est) {
             this.comparator = comparator; this.row = row;
             this.current = origin; this.fence = fence; this.est = est;
         }
 
-        public final long estimateSize() { return est; }
+        public final long estimateSize() { return (long)est; }
     }
 
     static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<K> {
         KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, long est) {
+                       Node<K,V> origin, K fence, int est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3128,7 +3331,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.val != null &&
+                        (n = b.next) != null && n.value != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3149,10 +3352,10 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if (e.val != null)
+                if ((v = e.value) != null && v != e)
                     action.accept(k);
             }
         }
@@ -3163,12 +3366,12 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if (e.val != null) {
+                if ((v = e.value) != null && v != e) {
                     current = e.next;
                     action.accept(k);
                     return true;
@@ -3190,23 +3393,21 @@
     }
     // factory method for KeySpliterator
     final KeySpliterator<K,V> keySpliterator() {
-        Index<K,V> h; Node<K,V> n; long est;
-        VarHandle.acquireFence();
-        if ((h = head) == null) {
-            n = null;
-            est = 0L;
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // ensure h corresponds to origin p
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                               0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
         }
-        else {
-            n = h.node;
-            est = getAdderCount();
-        }
-        return new KeySpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<V> {
         ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, long est) {
+                       Node<K,V> origin, K fence, int est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3218,7 +3419,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.val != null &&
+                        (n = b.next) != null && n.value != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3239,11 +3440,13 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; V v;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.val) != null)
-                    action.accept(v);
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
+                }
             }
         }
 
@@ -3253,14 +3456,15 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; V v;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.val) != null) {
+                if ((v = e.value) != null && v != e) {
                     current = e.next;
-                    action.accept(v);
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
                     return true;
                 }
             }
@@ -3276,23 +3480,21 @@
 
     // Almost the same as keySpliterator()
     final ValueSpliterator<K,V> valueSpliterator() {
-        Index<K,V> h; Node<K,V> n; long est;
-        VarHandle.acquireFence();
-        if ((h = head) == null) {
-            n = null;
-            est = 0L;
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
         }
-        else {
-            n = h.node;
-            est = getAdderCount();
-        }
-        return new ValueSpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<Map.Entry<K,V>> {
         EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                         Node<K,V> origin, K fence, long est) {
+                         Node<K,V> origin, K fence, int est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3304,7 +3506,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.val != null &&
+                        (n = b.next) != null && n.value != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3325,12 +3527,13 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; V v;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.val) != null) {
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
                 }
             }
         }
@@ -3341,15 +3544,16 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; V v;
+                K k; Object v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.val) != null) {
+                if ((v = e.value) != null && v != e) {
                     current = e.next;
+                    @SuppressWarnings("unchecked") V vv = (V)v;
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
                     return true;
                 }
             }
@@ -3380,37 +3584,26 @@
 
     // Almost the same as keySpliterator()
     final EntrySpliterator<K,V> entrySpliterator() {
-        Index<K,V> h; Node<K,V> n; long est;
-        VarHandle.acquireFence();
-        if ((h = head) == null) {
-            n = null;
-            est = 0L;
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // almost same as key version
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
         }
-        else {
-            n = h.node;
-            est = getAdderCount();
-        }
-        return new EntrySpliterator<K,V>(comparator, h, n, null, est);
     }
 
-    // VarHandle mechanics
-    private static final VarHandle HEAD;
-    private static final VarHandle ADDER;
-    private static final VarHandle NEXT;
-    private static final VarHandle VAL;
-    private static final VarHandle RIGHT;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
-                                   Index.class);
-            ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
-                                    LongAdder.class);
-            NEXT = l.findVarHandle(Node.class, "next", Node.class);
-            VAL = l.findVarHandle(Node.class, "val", Object.class);
-            RIGHT = l.findVarHandle(Index.class, "right", Index.class);
+            HEAD = U.objectFieldOffset
+                (ConcurrentSkipListMap.class.getDeclaredField("head"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index 140bde4..2e11b17 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -35,18 +35,23 @@
 
 package java.util.concurrent;
 
-import java.lang.reflect.Field;
 import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.Spliterator;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
 /**
  * A scalable concurrent {@link NavigableSet} implementation based on
  * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
@@ -70,12 +75,12 @@
  * asynchronous nature of these sets, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- *
- * <p>Bulk operations that add, remove, or examine multiple elements,
- * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
- * are <em>not</em> guaranteed to be performed atomically.
- * For example, a {@code forEach} traversal concurrent with an {@code
- * addAll} operation might observe only some of the added elements.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterators implement all of the
  * <em>optional</em> methods of the {@link Set} and {@link Iterator}
@@ -84,10 +89,6 @@
  * because {@code null} arguments and return values cannot be reliably
  * distinguished from the absence of elements.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <E> the type of elements maintained by this set
  * @since 1.6
@@ -309,7 +310,9 @@
         Collection<?> c = (Collection<?>) o;
         try {
             return containsAll(c) && c.containsAll(this);
-        } catch (ClassCastException | NullPointerException unused) {
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
             return false;
         }
     }
@@ -324,7 +327,7 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified collection or any
      *         of its elements are null
      */
@@ -488,9 +491,9 @@
      * encounter order that is ascending order.  Overriding implementations
      * should document the reporting of additional characteristic values.
      *
-     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
-     * is {@code null} if the {@linkplain #comparator() set's comparator}
-     * is {@code null}.
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the set's comparator (see {@link #comparator()}) is {@code null}.
      * Otherwise, the spliterator's comparator is the same as or imposes the
      * same total ordering as the set's comparator.
      *
@@ -503,21 +506,18 @@
             : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
     }
 
-    /** Initializes map field; for use in clone. */
+    // Support for resetting map in clone
     private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        Field mapField = java.security.AccessController.doPrivileged(
-            (java.security.PrivilegedAction<Field>) () -> {
-                try {
-                    Field f = ConcurrentSkipListSet.class
-                        .getDeclaredField("m");
-                    f.setAccessible(true);
-                    return f;
-                } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
-                }});
+        U.putObjectVolatile(this, MAP, map);
+    }
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long MAP;
+    static {
         try {
-            mapField.set(this, map);
-        } catch (IllegalAccessException e) {
+            MAP = U.objectFieldOffset
+                (ConcurrentSkipListSet.class.getDeclaredField("m"));
+        } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
index 912204f..ebcbbef 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
@@ -34,8 +34,7 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.VarHandle;
-import java.lang.reflect.Field;
+import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
@@ -51,7 +50,6 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
-import jdk.internal.misc.SharedSecrets;
 
 // Android-changed: Removed javadoc link to collections framework docs
 /**
@@ -83,10 +81,6 @@
  * actions subsequent to the access or removal of that element from
  * the {@code CopyOnWriteArrayList} in another thread.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this list
@@ -135,17 +129,17 @@
      * @throws NullPointerException if the specified collection is null
      */
     public CopyOnWriteArrayList(Collection<? extends E> c) {
-        Object[] es;
+        Object[] elements;
         if (c.getClass() == CopyOnWriteArrayList.class)
-            es = ((CopyOnWriteArrayList<?>)c).getArray();
+            elements = ((CopyOnWriteArrayList<?>)c).getArray();
         else {
-            es = c.toArray();
+            elements = c.toArray();
             // defend against c.toArray (incorrectly) not returning Object[]
             // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
-            if (es.getClass() != Object[].class)
-                es = Arrays.copyOf(es, es.length, Object[].class);
+            if (elements.getClass() != Object[].class)
+                elements = Arrays.copyOf(elements, elements.length, Object[].class);
         }
-        setArray(es);
+        setArray(elements);
     }
 
     /**
@@ -181,19 +175,20 @@
      * static version of indexOf, to allow repeated calls without
      * needing to re-acquire array each time.
      * @param o element to search for
-     * @param es the array
-     * @param from first index to search
-     * @param to one past last index to search
+     * @param elements the array
+     * @param index first index to search
+     * @param fence one past last index to search
      * @return index of element, or -1 if absent
      */
-    private static int indexOfRange(Object o, Object[] es, int from, int to) {
+    private static int indexOf(Object o, Object[] elements,
+                               int index, int fence) {
         if (o == null) {
-            for (int i = from; i < to; i++)
-                if (es[i] == null)
+            for (int i = index; i < fence; i++)
+                if (elements[i] == null)
                     return i;
         } else {
-            for (int i = from; i < to; i++)
-                if (o.equals(es[i]))
+            for (int i = index; i < fence; i++)
+                if (o.equals(elements[i]))
                     return i;
         }
         return -1;
@@ -202,19 +197,18 @@
     /**
      * static version of lastIndexOf.
      * @param o element to search for
-     * @param es the array
-     * @param from index of first element of range, last element to search
-     * @param to one past last element of range, first element to search
+     * @param elements the array
+     * @param index first index to search
      * @return index of element, or -1 if absent
      */
-    private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
+    private static int lastIndexOf(Object o, Object[] elements, int index) {
         if (o == null) {
-            for (int i = to - 1; i >= from; i--)
-                if (es[i] == null)
+            for (int i = index; i >= 0; i--)
+                if (elements[i] == null)
                     return i;
         } else {
-            for (int i = to - 1; i >= from; i--)
-                if (o.equals(es[i]))
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elements[i]))
                     return i;
         }
         return -1;
@@ -229,15 +223,16 @@
      * @return {@code true} if this list contains the specified element
      */
     public boolean contains(Object o) {
-        return indexOf(o) >= 0;
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length) >= 0;
     }
 
     /**
      * {@inheritDoc}
      */
     public int indexOf(Object o) {
-        Object[] es = getArray();
-        return indexOfRange(o, es, 0, es.length);
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length);
     }
 
     /**
@@ -256,16 +251,16 @@
      * @throws IndexOutOfBoundsException if the specified index is negative
      */
     public int indexOf(E e, int index) {
-        Object[] es = getArray();
-        return indexOfRange(e, es, index, es.length);
+        Object[] elements = getArray();
+        return indexOf(e, elements, index, elements.length);
     }
 
     /**
      * {@inheritDoc}
      */
     public int lastIndexOf(Object o) {
-        Object[] es = getArray();
-        return lastIndexOfRange(o, es, 0, es.length);
+        Object[] elements = getArray();
+        return lastIndexOf(o, elements, elements.length - 1);
     }
 
     /**
@@ -285,8 +280,8 @@
      *         than or equal to the current size of this list
      */
     public int lastIndexOf(E e, int index) {
-        Object[] es = getArray();
-        return lastIndexOfRange(e, es, 0, index + 1);
+        Object[] elements = getArray();
+        return lastIndexOf(e, elements, index);
     }
 
     /**
@@ -301,9 +296,6 @@
             CopyOnWriteArrayList<E> clone =
                 (CopyOnWriteArrayList<E>) super.clone();
             clone.resetLock();
-            // Unlike in readObject, here we cannot visibility-piggyback on the
-            // volatile write in setArray().
-            VarHandle.releaseFence();
             return clone;
         } catch (CloneNotSupportedException e) {
             // this shouldn't happen, since we are Cloneable
@@ -325,7 +317,8 @@
      * @return an array containing all the elements in this list
      */
     public Object[] toArray() {
-        return getArray().clone();
+        Object[] elements = getArray();
+        return Arrays.copyOf(elements, elements.length);
     }
 
     /**
@@ -368,12 +361,12 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        Object[] es = getArray();
-        int len = es.length;
+        Object[] elements = getArray();
+        int len = elements.length;
         if (a.length < len)
-            return (T[]) Arrays.copyOf(es, len, a.getClass());
+            return (T[]) Arrays.copyOf(elements, len, a.getClass());
         else {
-            System.arraycopy(es, 0, a, 0, len);
+            System.arraycopy(elements, 0, a, 0, len);
             if (a.length > len)
                 a[len] = null;
             return a;
@@ -383,7 +376,7 @@
     // Positional Access Operations
 
     @SuppressWarnings("unchecked")
-    static <E> E elementAt(Object[] a, int index) {
+    private E get(Object[] a, int index) {
         return (E) a[index];
     }
 
@@ -397,7 +390,7 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E get(int index) {
-        return elementAt(getArray(), index);
+        return get(getArray(), index);
     }
 
     /**
@@ -408,13 +401,17 @@
      */
     public E set(int index, E element) {
         synchronized (lock) {
-            Object[] es = getArray();
-            E oldValue = elementAt(es, index);
+            Object[] elements = getArray();
+            E oldValue = get(elements, index);
 
             if (oldValue != element) {
-                es = es.clone();
-                es[index] = element;
-                setArray(es);
+                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
+                setArray(elements);
             }
             return oldValue;
         }
@@ -428,11 +425,11 @@
      */
     public boolean add(E e) {
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
-            es = Arrays.copyOf(es, len + 1);
-            es[len] = e;
-            setArray(es);
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
             return true;
         }
     }
@@ -446,18 +443,18 @@
      */
     public void add(int index, E element) {
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
+            Object[] elements = getArray();
+            int len = elements.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             Object[] newElements;
             int numMoved = len - index;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(es, len + 1);
+                newElements = Arrays.copyOf(elements, len + 1);
             else {
                 newElements = new Object[len + 1];
-                System.arraycopy(es, 0, newElements, 0, index);
-                System.arraycopy(es, index, newElements, index + 1,
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index, newElements, index + 1,
                                  numMoved);
             }
             newElements[index] = element;
@@ -474,20 +471,19 @@
      */
     public E remove(int index) {
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
-            E oldValue = elementAt(es, index);
+            Object[] elements = getArray();
+            int len = elements.length;
+            E oldValue = get(elements, index);
             int numMoved = len - index - 1;
-            Object[] newElements;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(es, len - 1);
+                setArray(Arrays.copyOf(elements, len - 1));
             else {
-                newElements = new Object[len - 1];
-                System.arraycopy(es, 0, newElements, 0, index);
-                System.arraycopy(es, index + 1, newElements, index,
+                Object[] newElements = new Object[len - 1];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index + 1, newElements, index,
                                  numMoved);
+                setArray(newElements);
             }
-            setArray(newElements);
             return oldValue;
         }
     }
@@ -506,8 +502,8 @@
      */
     public boolean remove(Object o) {
         Object[] snapshot = getArray();
-        int index = indexOfRange(o, snapshot, 0, snapshot.length);
-        return index >= 0 && remove(o, snapshot, index);
+        int index = indexOf(o, snapshot, 0, snapshot.length);
+        return (index < 0) ? false : remove(o, snapshot, index);
     }
 
     /**
@@ -531,7 +527,7 @@
                     return false;
                 if (current[index] == o)
                     break findIndex;
-                index = indexOfRange(o, current, index, len);
+                index = indexOf(o, current, index, len);
                 if (index < 0)
                     return false;
             }
@@ -559,19 +555,19 @@
      */
     void removeRange(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
+            Object[] elements = getArray();
+            int len = elements.length;
 
             if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
                 throw new IndexOutOfBoundsException();
             int newlen = len - (toIndex - fromIndex);
             int numMoved = len - toIndex;
             if (numMoved == 0)
-                setArray(Arrays.copyOf(es, newlen));
+                setArray(Arrays.copyOf(elements, newlen));
             else {
                 Object[] newElements = new Object[newlen];
-                System.arraycopy(es, 0, newElements, 0, fromIndex);
-                System.arraycopy(es, toIndex, newElements,
+                System.arraycopy(elements, 0, newElements, 0, fromIndex);
+                System.arraycopy(elements, toIndex, newElements,
                                  fromIndex, numMoved);
                 setArray(newElements);
             }
@@ -586,8 +582,8 @@
      */
     public boolean addIfAbsent(E e) {
         Object[] snapshot = getArray();
-        return indexOfRange(e, snapshot, 0, snapshot.length) < 0
-            && addIfAbsent(e, snapshot);
+        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
+            addIfAbsent(e, snapshot);
     }
 
     /**
@@ -605,7 +601,7 @@
                     if (current[i] != snapshot[i]
                         && Objects.equals(e, current[i]))
                         return false;
-                if (indexOfRange(e, current, common, len) >= 0)
+                if (indexOf(e, current, common, len) >= 0)
                         return false;
             }
             Object[] newElements = Arrays.copyOf(current, len + 1);
@@ -626,10 +622,10 @@
      * @see #contains(Object)
      */
     public boolean containsAll(Collection<?> c) {
-        Object[] es = getArray();
-        int len = es.length;
+        Object[] elements = getArray();
+        int len = elements.length;
         for (Object e : c) {
-            if (indexOfRange(e, es, 0, len) < 0)
+            if (indexOf(e, elements, 0, len) < 0)
                 return false;
         }
         return true;
@@ -644,16 +640,34 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 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;
+        }
     }
 
     /**
@@ -665,16 +679,34 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 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;
+        }
     }
 
     /**
@@ -693,18 +725,18 @@
         if (cs.length == 0)
             return 0;
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
+            Object[] elements = getArray();
+            int len = elements.length;
             int added = 0;
             // uniquify and compact elements in cs
             for (int i = 0; i < cs.length; ++i) {
                 Object e = cs[i];
-                if (indexOfRange(e, es, 0, len) < 0 &&
-                    indexOfRange(e, cs, 0, added) < 0)
+                if (indexOf(e, elements, 0, len) < 0 &&
+                    indexOf(e, cs, 0, added) < 0)
                     cs[added++] = e;
             }
             if (added > 0) {
-                Object[] newElements = Arrays.copyOf(es, len + added);
+                Object[] newElements = Arrays.copyOf(elements, len + added);
                 System.arraycopy(cs, 0, newElements, len, added);
                 setArray(newElements);
             }
@@ -738,16 +770,15 @@
         if (cs.length == 0)
             return false;
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
-            Object[] newElements;
+            Object[] elements = getArray();
+            int len = elements.length;
             if (len == 0 && cs.getClass() == Object[].class)
-                newElements = cs;
+                setArray(cs);
             else {
-                newElements = Arrays.copyOf(es, len + cs.length);
+                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
                 System.arraycopy(cs, 0, newElements, len, cs.length);
+                setArray(newElements);
             }
-            setArray(newElements);
             return true;
         }
     }
@@ -771,8 +802,8 @@
     public boolean addAll(int index, Collection<? extends E> c) {
         Object[] cs = c.toArray();
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
+            Object[] elements = getArray();
+            int len = elements.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             if (cs.length == 0)
@@ -780,11 +811,11 @@
             int numMoved = len - index;
             Object[] newElements;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(es, len + cs.length);
+                newElements = Arrays.copyOf(elements, len + cs.length);
             else {
                 newElements = new Object[len + cs.length];
-                System.arraycopy(es, 0, newElements, 0, index);
-                System.arraycopy(es, index,
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index,
                                  newElements, index + cs.length,
                                  numMoved);
             }
@@ -794,106 +825,65 @@
         }
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
     public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
+        if (action == null) throw new NullPointerException();
         for (Object x : getArray()) {
             @SuppressWarnings("unchecked") E e = (E) x;
             action.accept(e);
         }
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
     public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    // A tiny bit set implementation
-
-    private static long[] nBits(int n) {
-        return new long[((n - 1) >> 6) + 1];
-    }
-    private static void setBit(long[] bits, int i) {
-        bits[i >> 6] |= 1L << i;
-    }
-    private static boolean isClear(long[] bits, int i) {
-        return (bits[i >> 6] & (1L << i)) == 0;
-    }
-
-    private boolean bulkRemove(Predicate<? super E> filter) {
+        if (filter == null) throw new NullPointerException();
         synchronized (lock) {
-            return bulkRemove(filter, 0, getArray().length);
-        }
-    }
-
-    boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
-        // assert Thread.holdsLock(lock);
-        final Object[] es = getArray();
-        // Optimize for initial run of survivors
-        for (; i < end && !filter.test(elementAt(es, i)); i++)
-            ;
-        if (i < end) {
-            final int beg = i;
-            final long[] deathRow = nBits(end - beg);
-            int deleted = 1;
-            deathRow[0] = 1L;   // set bit 0
-            for (i = beg + 1; i < end; i++)
-                if (filter.test(elementAt(es, i))) {
-                    setBit(deathRow, i - beg);
-                    deleted++;
+            final Object[] elements = getArray();
+            final int len = elements.length;
+            int i;
+            for (i = 0; i < len; i++) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                if (filter.test(e)) {
+                    int newlen = i;
+                    final Object[] newElements = new Object[len - 1];
+                    System.arraycopy(elements, 0, newElements, 0, newlen);
+                    for (i++; i < len; i++) {
+                        @SuppressWarnings("unchecked") E x = (E) elements[i];
+                        if (!filter.test(x))
+                            newElements[newlen++] = x;
+                    }
+                    setArray((newlen == len - 1)
+                             ? newElements // one match => one copy
+                             : Arrays.copyOf(newElements, newlen));
+                    return true;
                 }
-            // Did filter reentrantly modify the list?
-            if (es != getArray())
-                throw new ConcurrentModificationException();
-            final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
-            int w = beg;
-            for (i = beg; i < end; i++)
-                if (isClear(deathRow, i - beg))
-                    newElts[w++] = es[i];
-            System.arraycopy(es, i, newElts, w, es.length - i);
-            setArray(newElts);
-            return true;
-        } else {
-            if (es != getArray())
-                throw new ConcurrentModificationException();
-            return false;
+            }
+            return false;       // zero matches => zero copies
         }
     }
 
     public void replaceAll(UnaryOperator<E> operator) {
+        if (operator == null) throw new NullPointerException();
         synchronized (lock) {
-            replaceAllRange(operator, 0, getArray().length);
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len);
+            for (int i = 0; i < len; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                newElements[i] = operator.apply(e);
+            }
+            setArray(newElements);
         }
     }
 
-    void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
-        // assert Thread.holdsLock(lock);
-        Objects.requireNonNull(operator);
-        final Object[] es = getArray().clone();
-        for (; i < end; i++)
-            es[i] = operator.apply(elementAt(es, i));
-        setArray(es);
-    }
-
     public void sort(Comparator<? super E> c) {
         synchronized (lock) {
-            sortRange(c, 0, getArray().length);
+            Object[] elements = getArray();
+            Object[] newElements = Arrays.copyOf(elements, elements.length);
+            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+            Arrays.sort(es, c);
+            setArray(newElements);
         }
     }
 
-    @SuppressWarnings("unchecked")
-    void sortRange(Comparator<? super E> c, int i, int end) {
-        // assert Thread.holdsLock(lock);
-        final Object[] es = getArray().clone();
-        Arrays.sort(es, i, end, (Comparator<Object>)c);
-        setArray(es);
-    }
-
     /**
      * Saves this list to a stream (that is, serializes it).
      *
@@ -908,12 +898,12 @@
 
         s.defaultWriteObject();
 
-        Object[] es = getArray();
+        Object[] elements = getArray();
         // Write out array length
-        s.writeInt(es.length);
+        s.writeInt(elements.length);
 
         // Write out all elements in the proper order.
-        for (Object element : es)
+        for (Object element : elements)
             s.writeObject(element);
     }
 
@@ -934,13 +924,12 @@
 
         // Read in array length and allocate array
         int len = s.readInt();
-        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
-        Object[] es = new Object[len];
+        Object[] elements = new Object[len];
 
         // Read in all elements in the proper order.
         for (int i = 0; i < len; i++)
-            es[i] = s.readObject();
-        setArray(es);
+            elements[i] = s.readObject();
+        setArray(elements);
     }
 
     /**
@@ -980,19 +969,13 @@
 
         List<?> list = (List<?>)o;
         Iterator<?> it = list.iterator();
-        for (Object element : getArray())
-            if (!it.hasNext() || !Objects.equals(element, it.next()))
+        Object[] elements = getArray();
+        for (int i = 0, len = elements.length; i < len; i++)
+            if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
                 return false;
-        return !it.hasNext();
-    }
-
-    private static int hashCodeOfRange(Object[] es, int from, int to) {
-        int hashCode = 1;
-        for (int i = from; i < to; i++) {
-            Object x = es[i];
-            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
-        }
-        return hashCode;
+        if (it.hasNext())
+            return false;
+        return true;
     }
 
     /**
@@ -1003,8 +986,10 @@
      * @return the hash code value for this list
      */
     public int hashCode() {
-        Object[] es = getArray();
-        return hashCodeOfRange(es, 0, es.length);
+        int hashCode = 1;
+        for (Object x : getArray())
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        return hashCode;
     }
 
     /**
@@ -1044,12 +1029,12 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public ListIterator<E> listIterator(int index) {
-        Object[] es = getArray();
-        int len = es.length;
+        Object[] elements = getArray();
+        int len = elements.length;
         if (index < 0 || index > len)
             throw new IndexOutOfBoundsException(outOfBounds(index, len));
 
-        return new COWIterator<E>(es, index);
+        return new COWIterator<E>(elements, index);
     }
 
     /**
@@ -1077,9 +1062,9 @@
         /** Index of element to be returned by subsequent call to next.  */
         private int cursor;
 
-        COWIterator(Object[] es, int initialCursor) {
+        COWIterator(Object[] elements, int initialCursor) {
             cursor = initialCursor;
-            snapshot = es;
+            snapshot = elements;
         }
 
         public boolean hasNext() {
@@ -1109,7 +1094,7 @@
         }
 
         public int previousIndex() {
-            return cursor - 1;
+            return cursor-1;
         }
 
         /**
@@ -1140,13 +1125,14 @@
         }
 
         @Override
+        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
             final int size = snapshot.length;
-            int i = cursor;
+            for (int i = cursor; i < size; i++) {
+                action.accept((E) snapshot[i]);
+            }
             cursor = size;
-            for (; i < size; i++)
-                action.accept(elementAt(snapshot, i));
         }
     }
 
@@ -1167,358 +1153,324 @@
      */
     public List<E> subList(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] es = getArray();
-            int len = es.length;
-            int size = toIndex - fromIndex;
-            if (fromIndex < 0 || toIndex > len || size < 0)
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
                 throw new IndexOutOfBoundsException();
-            return new COWSubList(es, fromIndex, size);
+            return new COWSubList<E>(this, fromIndex, toIndex);
         }
     }
 
     /**
      * 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 class COWSubList implements List<E>, RandomAccess {
+    private static class COWSubList<E>
+        extends AbstractList<E>
+        implements RandomAccess
+    {
+        private final CopyOnWriteArrayList<E> l;
         private final int offset;
         private int size;
         private Object[] expectedArray;
 
-        COWSubList(Object[] es, int offset, int size) {
-            // assert Thread.holdsLock(lock);
-            expectedArray = es;
-            this.offset = offset;
-            this.size = size;
+        // only call this holding l's lock
+        COWSubList(CopyOnWriteArrayList<E> list,
+                   int fromIndex, int toIndex) {
+            // assert Thread.holdsLock(list.lock);
+            l = list;
+            expectedArray = l.getArray();
+            offset = fromIndex;
+            size = toIndex - fromIndex;
         }
 
+        // only call this holding l's lock
         private void checkForComodification() {
-            // assert Thread.holdsLock(lock);
-            if (getArray() != expectedArray)
+            // assert Thread.holdsLock(l.lock);
+            if (l.getArray() != expectedArray)
                 throw new ConcurrentModificationException();
         }
 
-        private Object[] getArrayChecked() {
-            // assert Thread.holdsLock(lock);
-            Object[] a = getArray();
-            if (a != expectedArray)
-                throw new ConcurrentModificationException();
-            return a;
-        }
-
+        // only call this holding l's lock
         private void rangeCheck(int index) {
-            // assert Thread.holdsLock(lock);
+            // assert Thread.holdsLock(l.lock);
             if (index < 0 || index >= size)
                 throw new IndexOutOfBoundsException(outOfBounds(index, size));
         }
 
-        private void rangeCheckForAdd(int index) {
-            // assert Thread.holdsLock(lock);
-            if (index < 0 || index > size)
-                throw new IndexOutOfBoundsException(outOfBounds(index, size));
-        }
-
-        public Object[] toArray() {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            return Arrays.copyOfRange(es, offset, offset + size);
-        }
-
-        @SuppressWarnings("unchecked")
-        public <T> T[] toArray(T[] a) {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            if (a.length < size)
-                return (T[]) Arrays.copyOfRange(
-                        es, offset, offset + size, a.getClass());
-            else {
-                System.arraycopy(es, offset, a, 0, size);
-                if (a.length > size)
-                    a[size] = null;
-                return a;
-            }
-        }
-
-        public int indexOf(Object o) {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            int i = indexOfRange(o, es, offset, offset + size);
-            return (i == -1) ? -1 : i - offset;
-        }
-
-        public int lastIndexOf(Object o) {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            int i = lastIndexOfRange(o, es, offset, offset + size);
-            return (i == -1) ? -1 : i - offset;
-        }
-
-        public boolean contains(Object o) {
-            return indexOf(o) >= 0;
-        }
-
-        public boolean containsAll(Collection<?> c) {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            for (Object o : c)
-                if (indexOfRange(o, es, offset, offset + size) < 0)
-                    return false;
-            return true;
-        }
-
-        public boolean isEmpty() {
-            return size() == 0;
-        }
-
-        public String toString() {
-            return Arrays.toString(toArray());
-        }
-
-        public int hashCode() {
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-            return hashCodeOfRange(es, offset, offset + size);
-        }
-
-        public boolean equals(Object o) {
-            if (o == this)
-                return true;
-            if (!(o instanceof List))
-                return false;
-            Iterator<?> it = ((List<?>)o).iterator();
-
-            final Object[] es;
-            final int offset;
-            final int size;
-            synchronized (lock) {
-                es = getArrayChecked();
-                offset = this.offset;
-                size = this.size;
-            }
-
-            for (int i = offset, end = offset + size; i < end; i++)
-                if (!it.hasNext() || !Objects.equals(es[i], it.next()))
-                    return false;
-            return !it.hasNext();
-        }
-
         public E set(int index, E element) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E x = CopyOnWriteArrayList.this.set(offset + index, element);
-                expectedArray = getArray();
+                E x = l.set(index+offset, element);
+                expectedArray = l.getArray();
                 return x;
             }
         }
 
         public E get(int index) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                return CopyOnWriteArrayList.this.get(offset + index);
+                return l.get(index+offset);
             }
         }
 
         public int size() {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 checkForComodification();
                 return size;
             }
         }
 
-        public boolean add(E element) {
-            synchronized (lock) {
-                checkForComodification();
-                CopyOnWriteArrayList.this.add(offset + size, element);
-                expectedArray = getArray();
-                size++;
-            }
-            return true;
-        }
-
         public void add(int index, E element) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 checkForComodification();
-                rangeCheckForAdd(index);
-                CopyOnWriteArrayList.this.add(offset + index, element);
-                expectedArray = getArray();
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                l.add(index+offset, element);
+                expectedArray = l.getArray();
                 size++;
             }
         }
 
-        public boolean addAll(Collection<? extends E> c) {
-            synchronized (lock) {
-                final Object[] oldArray = getArrayChecked();
-                boolean modified =
-                    CopyOnWriteArrayList.this.addAll(offset + size, c);
-                size += (expectedArray = getArray()).length - oldArray.length;
-                return modified;
-            }
-        }
-
-        public boolean addAll(int index, Collection<? extends E> c) {
-            synchronized (lock) {
-                rangeCheckForAdd(index);
-                final Object[] oldArray = getArrayChecked();
-                boolean modified =
-                    CopyOnWriteArrayList.this.addAll(offset + index, c);
-                size += (expectedArray = getArray()).length - oldArray.length;
-                return modified;
-            }
-        }
-
         public void clear() {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 checkForComodification();
-                removeRange(offset, offset + size);
-                expectedArray = getArray();
+                l.removeRange(offset, offset+size);
+                expectedArray = l.getArray();
                 size = 0;
             }
         }
 
         public E remove(int index) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E result = CopyOnWriteArrayList.this.remove(offset + index);
-                expectedArray = getArray();
+                E result = l.remove(index+offset);
+                expectedArray = l.getArray();
                 size--;
                 return result;
             }
         }
 
         public boolean remove(Object o) {
-            synchronized (lock) {
-                checkForComodification();
-                int index = indexOf(o);
-                if (index == -1)
-                    return false;
-                remove(index);
-                return true;
-            }
+            int index = indexOf(o);
+            if (index == -1)
+                return false;
+            remove(index);
+            return true;
         }
 
         public Iterator<E> iterator() {
-            return listIterator(0);
-        }
-
-        public ListIterator<E> listIterator() {
-            return listIterator(0);
+            synchronized (l.lock) {
+                checkForComodification();
+                return new COWSubListIterator<E>(l, 0, offset, size);
+            }
         }
 
         public ListIterator<E> listIterator(int index) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 checkForComodification();
-                rangeCheckForAdd(index);
-                return new COWSubListIterator<E>(
-                    CopyOnWriteArrayList.this, index, offset, size);
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                return new COWSubListIterator<E>(l, index, offset, size);
             }
         }
 
         public List<E> subList(int fromIndex, int toIndex) {
-            synchronized (lock) {
+            synchronized (l.lock) {
                 checkForComodification();
                 if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
                     throw new IndexOutOfBoundsException();
-                return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
+                return new COWSubList<E>(l, fromIndex + offset,
+                                         toIndex + offset);
             }
         }
 
         public void forEach(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            int i, end; final Object[] es;
-            synchronized (lock) {
-                es = getArrayChecked();
-                i = offset;
-                end = i + size;
+            if (action == null) throw new NullPointerException();
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            for (int i = lo; i < hi; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) a[i];
+                action.accept(e);
             }
-            for (; i < end; i++)
-                action.accept(elementAt(es, i));
         }
 
         public void replaceAll(UnaryOperator<E> operator) {
-            synchronized (lock) {
-                checkForComodification();
-                replaceAllRange(operator, offset, offset + size);
-                expectedArray = getArray();
+            if (operator == null) throw new NullPointerException();
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                for (int i = lo; i < hi; ++i) {
+                    @SuppressWarnings("unchecked") E e = (E) elements[i];
+                    newElements[i] = operator.apply(e);
+                }
+                l.setArray(expectedArray = newElements);
             }
         }
 
         public void sort(Comparator<? super E> c) {
-            synchronized (lock) {
-                checkForComodification();
-                sortRange(c, offset, offset + size);
-                expectedArray = getArray();
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+                Arrays.sort(es, lo, hi, c);
+                l.setArray(expectedArray = newElements);
             }
         }
 
         public boolean removeAll(Collection<?> c) {
-            Objects.requireNonNull(c);
-            return bulkRemove(e -> c.contains(e));
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (!c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[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);
+                    }
+                }
+            }
+            return removed;
         }
 
         public boolean retainAll(Collection<?> c) {
-            Objects.requireNonNull(c);
-            return bulkRemove(e -> !c.contains(e));
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[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);
+                    }
+                }
+            }
+            return removed;
         }
 
         public boolean removeIf(Predicate<? super E> filter) {
-            Objects.requireNonNull(filter);
-            return bulkRemove(filter);
-        }
-
-        private boolean bulkRemove(Predicate<? super E> filter) {
-            synchronized (lock) {
-                final Object[] oldArray = getArrayChecked();
-                boolean modified = CopyOnWriteArrayList.this.bulkRemove(
-                    filter, offset, offset + size);
-                size += (expectedArray = getArray()).length - oldArray.length;
-                return modified;
+            if (filter == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) elements[i];
+                        if (!filter.test(e))
+                            temp[newSize++] = e;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[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);
+                    }
+                }
             }
+            return removed;
         }
 
         public Spliterator<E> spliterator() {
-            synchronized (lock) {
-                return Spliterators.spliterator(
-                        getArrayChecked(), offset, offset + size,
-                        Spliterator.IMMUTABLE | Spliterator.ORDERED);
-            }
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            return Spliterators.spliterator
+                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
         }
 
     }
@@ -1531,7 +1483,7 @@
         COWSubListIterator(List<E> l, int index, int offset, int size) {
             this.offset = offset;
             this.size = size;
-            it = l.listIterator(index + offset);
+            it = l.listIterator(index+offset);
         }
 
         public boolean hasNext() {
@@ -1580,27 +1532,23 @@
         @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
-            while (hasNext()) {
+            while (nextIndex() < size) {
                 action.accept(it.next());
             }
         }
     }
 
-    /** Initializes the lock; for use when deserializing or cloning. */
+    // Support for resetting lock while deserializing
     private void resetLock() {
-        Field lockField = java.security.AccessController.doPrivileged(
-            (java.security.PrivilegedAction<Field>) () -> {
-                try {
-                    Field f = CopyOnWriteArrayList.class
-                        .getDeclaredField("lock");
-                    f.setAccessible(true);
-                    return f;
-                } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
-                }});
+        U.putObjectVolatile(this, LOCK, new Object());
+    }
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long LOCK;
+    static {
         try {
-            lockField.set(this, new Object());
-        } catch (IllegalAccessException e) {
+            LOCK = U.objectFieldOffset
+                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
+        } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index b14a3e8..fb707dd 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -45,8 +45,13 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
 /**
- * A {@link Set} that uses an internal {@link CopyOnWriteArrayList}
+ * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
  * for all of its operations.  Thus, it shares the same basic properties:
  * <ul>
  *  <li>It is best suited for applications in which set sizes generally
@@ -86,10 +91,6 @@
  *   }
  * }}</pre>
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @see CopyOnWriteArrayList
  * @since 1.5
  * @author Doug Lea
@@ -340,10 +341,10 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this set contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
@@ -363,10 +364,10 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this set contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
@@ -411,16 +412,10 @@
                 && compareSets(al.getArray(), (Set<?>) o) == 0);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
     public boolean removeIf(Predicate<? super E> filter) {
         return al.removeIf(filter);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
     public void forEach(Consumer<? super E> action) {
         al.forEach(action);
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
index a91d12d..a29208e 100644
--- a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
+++ b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
@@ -35,9 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 /**
  * A {@link ForkJoinTask} with a completion action performed when
  * triggered and there are no remaining pending actions.
@@ -57,7 +54,8 @@
  * decremented; otherwise, the completion action is performed, and if
  * this completer itself has a completer, the process is continued
  * with its completer.  As is the case with related synchronization
- * components such as {@link Phaser} and {@link Semaphore}, these methods
+ * components such as {@link java.util.concurrent.Phaser Phaser} and
+ * {@link java.util.concurrent.Semaphore Semaphore}, these methods
  * affect only internal counts; they do not establish any further
  * internal bookkeeping. In particular, the identities of pending
  * tasks are not maintained. As illustrated below, you can create
@@ -119,114 +117,102 @@
  * to complete for some elements than others, either because of
  * intrinsic variation (for example I/O) or auxiliary effects such as
  * garbage collection.  Because CountedCompleters provide their own
- * continuations, other tasks need not block waiting to perform them.
+ * continuations, other threads need not block waiting to perform
+ * them.
  *
- * <p>For example, here is an initial version of a utility method that
- * uses divide-by-two recursive decomposition to divide work into
- * single pieces (leaf tasks). Even when work is split into individual
- * calls, tree-based techniques are usually preferable to directly
- * forking leaf tasks, because they reduce inter-thread communication
- * and improve load balancing. In the recursive case, the second of
- * each pair of subtasks to finish triggers completion of their parent
+ * <p>For example, here is an initial version of a class that uses
+ * divide-by-two recursive decomposition to divide work into single
+ * pieces (leaf tasks). Even when work is split into individual calls,
+ * tree-based techniques are usually preferable to directly forking
+ * leaf tasks, because they reduce inter-thread communication and
+ * improve load balancing. In the recursive case, the second of each
+ * pair of subtasks to finish triggers completion of its parent
  * (because no result combination is performed, the default no-op
  * implementation of method {@code onCompletion} is not overridden).
- * The utility method sets up the root task and invokes it (here,
- * implicitly using the {@link ForkJoinPool#commonPool()}).  It is
- * straightforward and reliable (but not optimal) to always set the
- * pending count to the number of child tasks and call {@code
- * tryComplete()} immediately before returning.
+ * A static utility method sets up the base task and invokes it
+ * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
  *
  * <pre> {@code
- * public static <E> void forEach(E[] array, Consumer<E> action) {
- *   class Task extends CountedCompleter<Void> {
- *     final int lo, hi;
- *     Task(Task parent, int lo, int hi) {
- *       super(parent); this.lo = lo; this.hi = hi;
- *     }
+ * class MyOperation<E> { void apply(E e) { ... }  }
  *
- *     public void compute() {
- *       if (hi - lo >= 2) {
- *         int mid = (lo + hi) >>> 1;
- *         // must set pending count before fork
- *         setPendingCount(2);
- *         new Task(this, mid, hi).fork(); // right child
- *         new Task(this, lo, mid).fork(); // left child
- *       }
- *       else if (hi > lo)
- *         action.accept(array[lo]);
- *       tryComplete();
- *     }
+ * class ForEach<E> extends CountedCompleter<Void> {
+ *
+ *   public static <E> void forEach(E[] array, MyOperation<E> op) {
+ *     new ForEach<E>(null, array, op, 0, array.length).invoke();
  *   }
- *   new Task(null, 0, array.length).invoke();
+ *
+ *   final E[] array; final MyOperation<E> op; final int lo, hi;
+ *   ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
+ *   }
+ *
+ *   public void compute() { // version 1
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(2); // must set pending count before fork
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).fork(); // left child
+ *     }
+ *     else if (hi > lo)
+ *       op.apply(array[lo]);
+ *     tryComplete();
+ *   }
  * }}</pre>
  *
  * This design can be improved by noticing that in the recursive case,
  * the task has nothing to do after forking its right task, so can
  * directly invoke its left task before returning. (This is an analog
- * of tail recursion removal.)  Also, when the last action in a task
- * is to fork or invoke a subtask (a "tail call"), the call to {@code
- * tryComplete()} can be optimized away, at the cost of making the
- * pending count look "off by one".
+ * of tail recursion removal.)  Also, because the task returns upon
+ * executing its left task (rather than falling through to invoke
+ * {@code tryComplete}) the pending count is set to one:
  *
  * <pre> {@code
- *     public void compute() {
- *       if (hi - lo >= 2) {
- *         int mid = (lo + hi) >>> 1;
- *         setPendingCount(1); // looks off by one, but correct!
- *         new Task(this, mid, hi).fork(); // right child
- *         new Task(this, lo, mid).compute(); // direct invoke
- *       } else {
- *         if (hi > lo)
- *           action.accept(array[lo]);
- *         tryComplete();
- *       }
- *     }}</pre>
- *
- * As a further optimization, notice that the left task need not even exist.
- * Instead of creating a new one, we can continue using the original task,
- * and add a pending count for each fork.  Additionally, because no task
- * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
- * {@code tryComplete} can be replaced with {@link #propagateCompletion}.
- *
- * <pre> {@code
- *     public void compute() {
- *       int n = hi - lo;
- *       for (; n >= 2; n /= 2) {
- *         addToPendingCount(1);
- *         new Task(this, lo + n/2, lo + n).fork();
- *       }
- *       if (n > 0)
- *         action.accept(array[lo]);
- *       propagateCompletion();
- *     }}</pre>
- *
- * When pending counts can be precomputed, they can be established in
- * the constructor:
- *
- * <pre> {@code
- * public static <E> void forEach(E[] array, Consumer<E> action) {
- *   class Task extends CountedCompleter<Void> {
- *     final int lo, hi;
- *     Task(Task parent, int lo, int hi) {
- *       super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
- *       this.lo = lo; this.hi = hi;
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 2
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(1); // only one pending
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
  *     }
- *
- *     public void compute() {
- *       for (int n = hi - lo; n >= 2; n /= 2)
- *         new Task(this, lo + n/2, lo + n).fork();
- *       action.accept(array[lo]);
- *       propagateCompletion();
+ *     else {
+ *       if (hi > lo)
+ *         op.apply(array[lo]);
+ *       tryComplete();
  *     }
  *   }
- *   if (array.length > 0)
- *     new Task(null, 0, array.length).invoke();
  * }}</pre>
  *
- * Additional optimizations of such classes might entail specializing
- * classes for leaf steps, subdividing by say, four, instead of two
- * per iteration, and using an adaptive threshold instead of always
- * subdividing down to single elements.
+ * As a further optimization, notice that the left task need not even exist.
+ * Instead of creating a new one, we can iterate using the original task,
+ * and add a pending count for each fork.  Additionally, because no task
+ * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
+ * {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
+ *
+ * <pre> {@code
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 3
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       new ForEach(this, array, op, mid, h).fork(); // right child
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       op.apply(array[l]);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * Additional optimizations of such classes might entail precomputing
+ * pending counts so that they can be established in constructors,
+ * specializing classes for leaf steps, subdividing by say, four,
+ * instead of two per iteration, and using an adaptive threshold
+ * instead of always subdividing down to single elements.
  *
  * <p><b>Searching.</b> A tree of CountedCompleters can search for a
  * value or property in different parts of a data structure, and
@@ -538,7 +524,7 @@
      * @param delta the value to add
      */
     public final void addToPendingCount(int delta) {
-        PENDING.getAndAdd(this, delta);
+        U.getAndAddInt(this, PENDING, delta);
     }
 
     /**
@@ -550,7 +536,7 @@
      * @return {@code true} if successful
      */
     public final boolean compareAndSetPendingCount(int expected, int count) {
-        return PENDING.compareAndSet(this, expected, count);
+        return U.compareAndSwapInt(this, PENDING, expected, count);
     }
 
     /**
@@ -562,7 +548,7 @@
     public final int decrementPendingCountUnlessZero() {
         int c;
         do {} while ((c = pending) != 0 &&
-                     !PENDING.weakCompareAndSet(this, c, c - 1));
+                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
         return c;
     }
 
@@ -595,7 +581,7 @@
                     return;
                 }
             }
-            else if (PENDING.weakCompareAndSet(a, c, c - 1))
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
                 return;
         }
     }
@@ -610,7 +596,7 @@
      * not, be invoked for each completer in a computation.
      */
     public final void propagateCompletion() {
-        CountedCompleter<?> a = this, s;
+        CountedCompleter<?> a = this, s = a;
         for (int c;;) {
             if ((c = a.pending) == 0) {
                 if ((a = (s = a).completer) == null) {
@@ -618,7 +604,7 @@
                     return;
                 }
             }
-            else if (PENDING.weakCompareAndSet(a, c, c - 1))
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
                 return;
         }
     }
@@ -663,7 +649,7 @@
         for (int c;;) {
             if ((c = pending) == 0)
                 return this;
-            else if (PENDING.weakCompareAndSet(this, c, c - 1))
+            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
                 return null;
         }
     }
@@ -735,7 +721,7 @@
         CountedCompleter<?> a = this, s = a;
         while (a.onExceptionalCompletion(ex, s) &&
                (a = (s = a).completer) != null && a.status >= 0 &&
-               isExceptionalStatus(a.recordExceptionalCompletion(ex)))
+               a.recordExceptionalCompletion(ex) == EXCEPTIONAL)
             ;
     }
 
@@ -767,15 +753,15 @@
      */
     protected void setRawResult(T t) { }
 
-    // VarHandle mechanics
-    private static final VarHandle PENDING;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PENDING;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
-
+            PENDING = U.objectFieldOffset
+                (CountedCompleter.class.getDeclaredField("pending"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
index 269bec4..5e018f1 100644
--- a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -82,7 +82,8 @@
  *   public Solver(float[][] matrix) {
  *     data = matrix;
  *     N = matrix.length;
- *     Runnable barrierAction = () -> mergeRows(...);
+ *     Runnable barrierAction =
+ *       new Runnable() { public void run() { mergeRows(...); }};
  *     barrier = new CyclicBarrier(N, barrierAction);
  *
  *     List<Thread> threads = new ArrayList<>(N);
@@ -131,10 +132,10 @@
  * <i>happen-before</i> actions following a successful return from the
  * corresponding {@code await()} in other threads.
  *
+ * @since 1.5
  * @see CountDownLatch
  *
  * @author Doug Lea
- * @since 1.5
  */
 public class CyclicBarrier {
     /**
@@ -149,8 +150,7 @@
      * but no subsequent reset.
      */
     private static class Generation {
-        Generation() {}                 // prevent access constructor creation
-        boolean broken;                 // initially false
+        boolean broken;         // initially false
     }
 
     /** The lock for guarding barrier entry */
diff --git a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
index bf0858d..04a83d9 100644
--- a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -41,11 +41,14 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * An unbounded {@linkplain BlockingQueue blocking queue} of
  * {@code Delayed} elements, in which an element can only be taken
@@ -60,15 +63,11 @@
  * returns the count of both expired and unexpired elements.
  * This queue does not permit null elements.
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
- * The Iterator provided in method {@link #iterator()} is <em>not</em>
- * guaranteed to traverse the elements of the DelayQueue in any
- * particular order.
- *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the DelayQueue in any particular order.
  *
  * @since 1.5
  * @author Doug Lea
@@ -323,13 +322,40 @@
     }
 
     /**
+     * Returns first element only if it is expired.
+     * Used only by drainTo.  Call only when holding lock.
+     */
+    private E peekExpired() {
+        // assert lock.isHeldByCurrentThread();
+        E first = q.peek();
+        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+            null : first;
+    }
+
+    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        return drainTo(c, Integer.MAX_VALUE);
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E e; (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
     }
 
     /**
@@ -339,7 +365,8 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -348,11 +375,8 @@
         lock.lock();
         try {
             int n = 0;
-            for (E first;
-                 n < maxElements
-                     && (first = q.peek()) != null
-                     && first.getDelay(NANOSECONDS) <= 0;) {
-                c.add(first);   // In this order, in case add() throws.
+            for (E e; n < maxElements && (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
                 q.poll();
                 ++n;
             }
@@ -523,7 +547,8 @@
         public E next() {
             if (cursor >= array.length)
                 throw new NoSuchElementException();
-            return (E)array[lastRet = cursor++];
+            lastRet = cursor;
+            return (E)array[cursor++];
         }
 
         public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Exchanger.java b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
index 38c43fe..f01a705 100644
--- a/ojluni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
@@ -36,10 +36,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.util.concurrent.locks.LockSupport;
-
 /**
  * A synchronization point at which threads can pair and swap elements
  * within pairs.  Each thread presents some object on entry to the
@@ -159,7 +155,9 @@
      * a value that is enough for common platforms.  Additionally,
      * extra care elsewhere is taken to avoid other false/unintended
      * sharing and to enhance locality, including adding padding (via
-     * @Contended) to Nodes, embedding "bound" as an Exchanger field.
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field,
+     * and reworking some park/unpark mechanics compared to
+     * LockSupport versions.
      *
      * The arena starts out with only one used slot. We expand the
      * effective arena size by tracking collisions; i.e., failed CASes
@@ -235,23 +233,29 @@
      * As is too common in this sort of code, methods are monolithic
      * because most of the logic relies on reads of fields that are
      * maintained as local variables so can't be nicely factored --
-     * mainly, here, bulky spin->yield->block/cancel code.  Note that
-     * field Node.item is not declared as volatile even though it is
-     * read by releasing threads, because they only do so after CAS
-     * operations that must precede access, and all uses by the owning
-     * thread are otherwise acceptably ordered by other operations.
-     * (Because the actual points of atomicity are slot CASes, it
-     * would also be legal for the write to Node.match in a release to
-     * be weaker than a full volatile write. However, this is not done
-     * because it could allow further postponement of the write,
-     * delaying progress.)
+     * mainly, here, bulky spin->yield->block/cancel code), and
+     * heavily dependent on intrinsics (Unsafe) to use inlined
+     * embedded CAS and related memory access operations (that tend
+     * not to be as readily inlined by dynamic compilers when they are
+     * hidden behind other methods that would more nicely name and
+     * encapsulate the intended effects). This includes the use of
+     * putOrderedX to clear fields of the per-thread Nodes between
+     * uses. Note that field Node.item is not declared as volatile
+     * even though it is read by releasing threads, because they only
+     * do so after CAS operations that must precede access, and all
+     * uses by the owning thread are otherwise acceptably ordered by
+     * other operations. (Because the actual points of atomicity are
+     * slot CASes, it would also be legal for the write to Node.match
+     * in a release to be weaker than a full volatile write. However,
+     * this is not done because it could allow further postponement of
+     * the write, delaying progress.)
      */
 
     /**
-     * The index distance (as a shift value) between any two used slots
-     * in the arena, spacing them out to avoid false sharing.
+     * The byte distance (as a shift value) between any two used slots
+     * in the arena.  1 << ASHIFT should be at least cacheline size.
      */
-    private static final int ASHIFT = 5;
+    private static final int ASHIFT = 7;
 
     /**
      * The maximum supported arena index. The maximum allocatable
@@ -354,31 +358,27 @@
      */
     private final Object arenaExchange(Object item, boolean timed, long ns) {
         Node[] a = arena;
-        int alen = a.length;
         Node p = participant.get();
         for (int i = p.index;;) {                      // access slot at i
-            int b, m, c;
-            int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
-            if (j < 0 || j >= alen)
-                j = alen - 1;
-            Node q = (Node)AA.getAcquire(a, j);
-            if (q != null && AA.compareAndSet(a, j, q, null)) {
+            int b, m, c; long j;                       // j is raw array offset
+            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
+            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
                 Object v = q.item;                     // release
                 q.match = item;
                 Thread w = q.parked;
                 if (w != null)
-                    LockSupport.unpark(w);
+                    U.unpark(w);
                 return v;
             }
             else if (i <= (m = (b = bound) & MMASK) && q == null) {
                 p.item = item;                         // offer
-                if (AA.compareAndSet(a, j, null, p)) {
+                if (U.compareAndSwapObject(a, j, null, p)) {
                     long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
                     Thread t = Thread.currentThread(); // wait
                     for (int h = p.hash, spins = SPINS;;) {
                         Object v = p.match;
                         if (v != null) {
-                            MATCH.setRelease(p, null);
+                            U.putOrderedObject(p, MATCH, null);
                             p.item = null;             // clear for next use
                             p.hash = h;
                             return v;
@@ -391,24 +391,22 @@
                                      (--spins & ((SPINS >>> 1) - 1)) == 0)
                                 Thread.yield();        // two yields per wait
                         }
-                        else if (AA.getAcquire(a, j) != p)
+                        else if (U.getObjectVolatile(a, j) != p)
                             spins = SPINS;       // releaser hasn't set match yet
                         else if (!t.isInterrupted() && m == 0 &&
                                  (!timed ||
                                   (ns = end - System.nanoTime()) > 0L)) {
+                            U.putObject(t, BLOCKER, this); // emulate LockSupport
                             p.parked = t;              // minimize window
-                            if (AA.getAcquire(a, j) == p) {
-                                if (ns == 0L)
-                                    LockSupport.park(this);
-                                else
-                                    LockSupport.parkNanos(this, ns);
-                            }
+                            if (U.getObjectVolatile(a, j) == p)
+                                U.park(false, ns);
                             p.parked = null;
+                            U.putObject(t, BLOCKER, null);
                         }
-                        else if (AA.getAcquire(a, j) == p &&
-                                 AA.compareAndSet(a, j, p, null)) {
+                        else if (U.getObjectVolatile(a, j) == p &&
+                                 U.compareAndSwapObject(a, j, p, null)) {
                             if (m != 0)                // try to shrink
-                                BOUND.compareAndSet(this, b, b + SEQ - 1);
+                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
                             p.item = null;
                             p.hash = h;
                             i = p.index >>>= 1;        // descend
@@ -430,7 +428,7 @@
                     i = (i != m || m == 0) ? m : m - 1;
                 }
                 else if ((c = p.collides) < m || m == FULL ||
-                         !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
+                         !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
                     p.collides = c + 1;
                     i = (i == 0) ? m : i - 1;          // cyclically traverse
                 }
@@ -459,24 +457,24 @@
 
         for (Node q;;) {
             if ((q = slot) != null) {
-                if (SLOT.compareAndSet(this, q, null)) {
+                if (U.compareAndSwapObject(this, SLOT, q, null)) {
                     Object v = q.item;
                     q.match = item;
                     Thread w = q.parked;
                     if (w != null)
-                        LockSupport.unpark(w);
+                        U.unpark(w);
                     return v;
                 }
                 // create arena on contention, but continue until slot null
                 if (NCPU > 1 && bound == 0 &&
-                    BOUND.compareAndSet(this, 0, SEQ))
+                    U.compareAndSwapInt(this, BOUND, 0, SEQ))
                     arena = new Node[(FULL + 2) << ASHIFT];
             }
             else if (arena != null)
                 return null; // caller must reroute to arenaExchange
             else {
                 p.item = item;
-                if (SLOT.compareAndSet(this, null, p))
+                if (U.compareAndSwapObject(this, SLOT, null, p))
                     break;
                 p.item = null;
             }
@@ -499,21 +497,19 @@
                 spins = SPINS;
             else if (!t.isInterrupted() && arena == null &&
                      (!timed || (ns = end - System.nanoTime()) > 0L)) {
+                U.putObject(t, BLOCKER, this);
                 p.parked = t;
-                if (slot == p) {
-                    if (ns == 0L)
-                        LockSupport.park(this);
-                    else
-                        LockSupport.parkNanos(this, ns);
-                }
+                if (slot == p)
+                    U.park(false, ns);
                 p.parked = null;
+                U.putObject(t, BLOCKER, null);
             }
-            else if (SLOT.compareAndSet(this, p, null)) {
+            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
                 v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
                 break;
             }
         }
-        MATCH.setRelease(p, null);
+        U.putOrderedObject(p, MATCH, null);
         p.item = null;
         p.hash = h;
         return v;
@@ -562,9 +558,8 @@
     @SuppressWarnings("unchecked")
     public V exchange(V x) throws InterruptedException {
         Object v;
-        Node[] a;
         Object item = (x == null) ? NULL_ITEM : x; // translate null args
-        if (((a = arena) != null ||
+        if ((arena != null ||
              (v = slotExchange(item, false, 0L)) == null) &&
             ((Thread.interrupted() || // disambiguates null return
               (v = arenaExchange(item, false, 0L)) == null)))
@@ -630,20 +625,33 @@
         return (v == NULL_ITEM) ? null : (V)v;
     }
 
-    // VarHandle mechanics
-    private static final VarHandle BOUND;
-    private static final VarHandle SLOT;
-    private static final VarHandle MATCH;
-    private static final VarHandle AA;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long BOUND;
+    private static final long SLOT;
+    private static final long MATCH;
+    private static final long BLOCKER;
+    private static final int ABASE;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
-            SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
-            MATCH = l.findVarHandle(Node.class, "match", Object.class);
-            AA = MethodHandles.arrayElementVarHandle(Node[].class);
+            BOUND = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("bound"));
+            SLOT = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("slot"));
+
+            MATCH = U.objectFieldOffset
+                (Node.class.getDeclaredField("match"));
+
+            BLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
+                throw new Error("Unsupported array scale");
+            // ABASE absorbs padding in front of element 0
+            ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/Executor.java b/ojluni/src/main/java/java/util/concurrent/Executor.java
index 378cacd..a615705 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executor.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executor.java
@@ -87,12 +87,14 @@
  *     this.executor = executor;
  *   }
  *
- *   public synchronized void execute(Runnable r) {
- *     tasks.add(() -> {
- *       try {
- *         r.run();
- *       } finally {
- *         scheduleNext();
+ *   public synchronized void execute(final Runnable r) {
+ *     tasks.add(new Runnable() {
+ *       public void run() {
+ *         try {
+ *           r.run();
+ *         } finally {
+ *           scheduleNext();
+ *         }
  *       }
  *     });
  *     if (active == null) {
diff --git a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index d60d3dd..a093844 100644
--- a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -56,11 +56,13 @@
  * void solve(Executor e,
  *            Collection<Callable<Result>> solvers)
  *     throws InterruptedException, ExecutionException {
- *   CompletionService<Result> cs
- *       = new ExecutorCompletionService<>(e);
- *   solvers.forEach(cs::submit);
- *   for (int i = solvers.size(); i > 0; i--) {
- *     Result r = cs.take().get();
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
+ *   for (Callable<Result> s : solvers)
+ *     ecs.submit(s);
+ *   int n = solvers.size();
+ *   for (int i = 0; i < n; ++i) {
+ *     Result r = ecs.take().get();
  *     if (r != null)
  *       use(r);
  *   }
@@ -74,31 +76,32 @@
  * void solve(Executor e,
  *            Collection<Callable<Result>> solvers)
  *     throws InterruptedException {
- *   CompletionService<Result> cs
- *       = new ExecutorCompletionService<>(e);
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
  *   int n = solvers.size();
  *   List<Future<Result>> futures = new ArrayList<>(n);
  *   Result result = null;
  *   try {
- *     solvers.forEach(solver -> futures.add(cs.submit(solver)));
- *     for (int i = n; i > 0; i--) {
+ *     for (Callable<Result> s : solvers)
+ *       futures.add(ecs.submit(s));
+ *     for (int i = 0; i < n; ++i) {
  *       try {
- *         Result r = cs.take().get();
+ *         Result r = ecs.take().get();
  *         if (r != null) {
  *           result = r;
  *           break;
  *         }
  *       } catch (ExecutionException ignore) {}
  *     }
- *   } finally {
- *     futures.forEach(future -> future.cancel(true));
+ *   }
+ *   finally {
+ *     for (Future<Result> f : futures)
+ *       f.cancel(true);
  *   }
  *
  *   if (result != null)
  *     use(result);
  * }}</pre>
- *
- * @since 1.5
  */
 public class ExecutorCompletionService<V> implements CompletionService<V> {
     private final Executor executor;
@@ -174,10 +177,6 @@
         this.completionQueue = completionQueue;
     }
 
-    /**
-     * @throws RejectedExecutionException {@inheritDoc}
-     * @throws NullPointerException       {@inheritDoc}
-     */
     public Future<V> submit(Callable<V> task) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task);
@@ -185,10 +184,6 @@
         return f;
     }
 
-    /**
-     * @throws RejectedExecutionException {@inheritDoc}
-     * @throws NullPointerException       {@inheritDoc}
-     */
     public Future<V> submit(Runnable task, V result) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task, result);
diff --git a/ojluni/src/main/java/java/util/concurrent/Executors.java b/ojluni/src/main/java/java/util/concurrent/Executors.java
index e8cc0c1..565fdeb 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executors.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executors.java
@@ -35,7 +35,6 @@
 
 package java.util.concurrent;
 
-import static java.lang.ref.Reference.reachabilityFence;
 import dalvik.annotation.optimization.ReachabilitySensitive;
 import java.security.AccessControlContext;
 import java.security.AccessControlException;
@@ -191,7 +190,9 @@
      * returned executor is guaranteed not to be reconfigurable to use
      * additional threads.
      *
-     * @param threadFactory the factory to use when creating new threads
+     * @param threadFactory the factory to use when creating new
+     * threads
+     *
      * @return the newly created single-threaded Executor
      * @throws NullPointerException if threadFactory is null
      */
@@ -230,7 +231,6 @@
      * will reuse previously constructed threads when they are
      * available, and uses the provided
      * ThreadFactory to create new threads when needed.
-     *
      * @param threadFactory the factory to use when creating new threads
      * @return the newly created thread pool
      * @throws NullPointerException if threadFactory is null
@@ -253,7 +253,6 @@
      * given time. Unlike the otherwise equivalent
      * {@code newScheduledThreadPool(1)} the returned executor is
      * guaranteed not to be reconfigurable to use additional threads.
-     *
      * @return the newly created scheduled executor
      */
     public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
@@ -272,9 +271,9 @@
      * equivalent {@code newScheduledThreadPool(1, threadFactory)}
      * the returned executor is guaranteed not to be reconfigurable to
      * use additional threads.
-     *
-     * @param threadFactory the factory to use when creating new threads
-     * @return the newly created scheduled executor
+     * @param threadFactory the factory to use when creating new
+     * threads
+     * @return a newly created scheduled executor
      * @throws NullPointerException if threadFactory is null
      */
     public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
@@ -287,7 +286,7 @@
      * given delay, or to execute periodically.
      * @param corePoolSize the number of threads to keep in the pool,
      * even if they are idle
-     * @return the newly created scheduled thread pool
+     * @return a newly created scheduled thread pool
      * @throws IllegalArgumentException if {@code corePoolSize < 0}
      */
     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
@@ -301,7 +300,7 @@
      * even if they are idle
      * @param threadFactory the factory to use when the executor
      * creates a new thread
-     * @return the newly created scheduled thread pool
+     * @return a newly created scheduled thread pool
      * @throws IllegalArgumentException if {@code corePoolSize < 0}
      * @throws NullPointerException if threadFactory is null
      */
@@ -463,9 +462,6 @@
             task.run();
             return result;
         }
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + task + "]";
-        }
     }
 
     /**
@@ -492,10 +488,6 @@
                 throw e.getException();
             }
         }
-
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + task + "]";
-        }
     }
 
     /**
@@ -551,10 +543,6 @@
                 throw e.getException();
             }
         }
-
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + task + "]";
-        }
     }
 
     /**
@@ -616,7 +604,7 @@
         public Thread newThread(final Runnable r) {
             return super.newThread(new Runnable() {
                 public void run() {
-                    AccessController.doPrivileged(new PrivilegedAction<>() {
+                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                         public Void run() {
                             Thread.currentThread().setContextClassLoader(ccl);
                             r.run();
@@ -633,79 +621,47 @@
      * of an ExecutorService implementation.
      */
     private static class DelegatedExecutorService
-            implements ExecutorService {
+            extends AbstractExecutorService {
         // Android-added: @ReachabilitySensitive
         // Needed for FinalizableDelegatedExecutorService below.
         @ReachabilitySensitive
         private final ExecutorService e;
         DelegatedExecutorService(ExecutorService executor) { e = executor; }
-        public void execute(Runnable command) {
-            try {
-                e.execute(command);
-            } finally { reachabilityFence(this); }
-        }
+        public void execute(Runnable command) { e.execute(command); }
         public void shutdown() { e.shutdown(); }
-        public List<Runnable> shutdownNow() {
-            try {
-                return e.shutdownNow();
-            } finally { reachabilityFence(this); }
-        }
-        public boolean isShutdown() {
-            try {
-                return e.isShutdown();
-            } finally { reachabilityFence(this); }
-        }
-        public boolean isTerminated() {
-            try {
-                return e.isTerminated();
-            } finally { reachabilityFence(this); }
-        }
+        public List<Runnable> shutdownNow() { return e.shutdownNow(); }
+        public boolean isShutdown() { return e.isShutdown(); }
+        public boolean isTerminated() { return e.isTerminated(); }
         public boolean awaitTermination(long timeout, TimeUnit unit)
             throws InterruptedException {
-            try {
-                return e.awaitTermination(timeout, unit);
-            } finally { reachabilityFence(this); }
+            return e.awaitTermination(timeout, unit);
         }
         public Future<?> submit(Runnable task) {
-            try {
-                return e.submit(task);
-            } finally { reachabilityFence(this); }
+            return e.submit(task);
         }
         public <T> Future<T> submit(Callable<T> task) {
-            try {
-                return e.submit(task);
-            } finally { reachabilityFence(this); }
+            return e.submit(task);
         }
         public <T> Future<T> submit(Runnable task, T result) {
-            try {
-                return e.submit(task, result);
-            } finally { reachabilityFence(this); }
+            return e.submit(task, result);
         }
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
             throws InterruptedException {
-            try {
-                return e.invokeAll(tasks);
-            } finally { reachabilityFence(this); }
+            return e.invokeAll(tasks);
         }
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                              long timeout, TimeUnit unit)
             throws InterruptedException {
-            try {
-                return e.invokeAll(tasks, timeout, unit);
-            } finally { reachabilityFence(this); }
+            return e.invokeAll(tasks, timeout, unit);
         }
         public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
             throws InterruptedException, ExecutionException {
-            try {
-                return e.invokeAny(tasks);
-            } finally { reachabilityFence(this); }
+            return e.invokeAny(tasks);
         }
         public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                                long timeout, TimeUnit unit)
             throws InterruptedException, ExecutionException, TimeoutException {
-            try {
-                return e.invokeAny(tasks, timeout, unit);
-            } finally { reachabilityFence(this); }
+            return e.invokeAny(tasks, timeout, unit);
         }
     }
 
@@ -714,7 +670,6 @@
         FinalizableDelegatedExecutorService(ExecutorService executor) {
             super(executor);
         }
-        @SuppressWarnings("deprecation")
         protected void finalize() {
             super.shutdown();
         }
diff --git a/ojluni/src/main/java/java/util/concurrent/Flow.java b/ojluni/src/main/java/java/util/concurrent/Flow.java
index 727a507..0231790 100644
--- a/ojluni/src/main/java/java/util/concurrent/Flow.java
+++ b/ojluni/src/main/java/java/util/concurrent/Flow.java
@@ -85,9 +85,9 @@
  *       this.executor = executor;
  *     }
  *     public synchronized void request(long n) {
- *       if (!completed) {
+ *       if (n != 0 && !completed) {
  *         completed = true;
- *         if (n <= 0) {
+ *         if (n < 0) {
  *           IllegalArgumentException ex = new IllegalArgumentException();
  *           executor.execute(() -> subscriber.onError(ex));
  *         } else {
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 98b9c76..04ad7d7 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -36,19 +36,15 @@
 package java.util.concurrent;
 
 import java.lang.Thread.UncaughtExceptionHandler;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.security.AccessController;
 import java.security.AccessControlContext;
-import java.security.Permission;
 import java.security.Permissions;
-import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.function.Predicate;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -67,8 +63,7 @@
  * tasks are submitted to the pool from external clients.  Especially
  * when setting <em>asyncMode</em> to true in constructors, {@code
  * ForkJoinPool}s may also be appropriate for use with event-style
- * tasks that are never joined. All worker threads are initialized
- * with {@link Thread#isDaemon} set {@code true}.
+ * tasks that are never joined.
  *
  * <p>A static {@link #commonPool()} is available and appropriate for
  * most applications. The common pool is used by any ForkJoinTask that
@@ -86,9 +81,7 @@
  * However, no such adjustments are guaranteed in the face of blocked
  * I/O or other unmanaged synchronization. The nested {@link
  * ManagedBlocker} interface enables extension of the kinds of
- * synchronization accommodated. The default policies may be
- * overridden using a constructor with parameters corresponding to
- * those documented in class {@link ThreadPoolExecutor}.
+ * synchronization accommodated.
  *
  * <p>In addition to execution and lifecycle control methods, this
  * class provides status check methods (for example
@@ -109,54 +102,48 @@
  * async event-style tasks that are not usually joined, in which case
  * there is little difference among choice of methods.
  *
- * <table class="plain">
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
  * <caption>Summary of task execution methods</caption>
  *  <tr>
  *    <td></td>
- *    <th scope="col"> Call from non-fork/join clients</th>
- *    <th scope="col"> Call from within fork/join computations</th>
+ *    <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
+ *    <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left"> Arrange async execution</th>
+ *    <td> <b>Arrange async execution</b></td>
  *    <td> {@link #execute(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#fork}</td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left"> Await and obtain result</th>
+ *    <td> <b>Await and obtain result</b></td>
  *    <td> {@link #invoke(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#invoke}</td>
  *  </tr>
  *  <tr>
- *    <th scope="row" style="text-align:left"> Arrange exec and obtain Future</th>
+ *    <td> <b>Arrange exec and obtain Future</b></td>
  *    <td> {@link #submit(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
  *  </tr>
  * </table>
  *
- * <p>The parameters used to construct the common pool may be controlled by
- * setting the following {@linkplain System#getProperty system properties}:
+ * <p>The common pool is by default constructed with default
+ * parameters, but these may be controlled by setting three
+ * {@linkplain System#getProperty system properties}:
  * <ul>
  * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
  * - the parallelism level, a non-negative integer
  * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
- * - the class name of a {@link ForkJoinWorkerThreadFactory}.
- * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
- * is used to load this class.
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}
  * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
- * - the class name of a {@link UncaughtExceptionHandler}.
- * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
- * is used to load this class.
+ * - the class name of a {@link UncaughtExceptionHandler}
  * <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
  * - the maximum number of allowed extra threads to maintain target
  * parallelism (default 256).
  * </ul>
- * If no thread factory is supplied via a system property, then the
- * common pool uses a factory that uses the system class loader as the
- * {@linkplain Thread#getContextClassLoader() thread context class loader}.
- * In addition, if a {@link SecurityManager} is present, then
- * the common pool uses a factory supplying threads that have no
- * {@link Permissions} enabled.
- *
+ * If a {@link SecurityManager} is present and no factory is
+ * specified, then the default pool uses a factory supplying
+ * threads that have no {@link Permissions} enabled.
+ * The system class loader is used to load these classes.
  * Upon any error in establishing these settings, default parameters
  * are used. It is possible to disable or limit the use of threads in
  * the common pool by setting the parallelism property to zero, and/or
@@ -186,22 +173,17 @@
      * functionality and control for a set of worker threads:
      * Submissions from non-FJ threads enter into submission queues.
      * Workers take these tasks and typically split them into subtasks
-     * that may be stolen by other workers. Work-stealing based on
-     * randomized scans generally leads to better throughput than
-     * "work dealing" in which producers assign tasks to idle threads,
-     * in part because threads that have finished other tasks before
-     * the signalled thread wakes up (which can be a long time) can
-     * take the task instead.  Preference rules give first priority to
-     * processing tasks from their own queues (LIFO or FIFO, depending
-     * on mode), then to randomized FIFO steals of tasks in other
-     * queues.  This framework began as vehicle for supporting
-     * tree-structured parallelism using work-stealing.  Over time,
-     * its scalability advantages led to extensions and changes to
-     * better support more diverse usage contexts.  Because most
-     * internal methods and nested classes are interrelated, their
-     * main rationale and descriptions are presented here; individual
-     * methods and nested classes contain only brief comments about
-     * details.
+     * that may be stolen by other workers.  Preference rules give
+     * first priority to processing tasks from their own queues (LIFO
+     * or FIFO, depending on mode), then to randomized FIFO steals of
+     * tasks in other queues.  This framework began as vehicle for
+     * supporting tree-structured parallelism using work-stealing.
+     * Over time, its scalability advantages led to extensions and
+     * changes to better support more diverse usage contexts.  Because
+     * most internal methods and nested classes are interrelated,
+     * their main rationale and descriptions are presented here;
+     * individual methods and nested classes contain only brief
+     * comments about details.
      *
      * WorkQueues
      * ==========
@@ -234,10 +216,9 @@
      *
      * (The actual code needs to null-check and size-check the array,
      * uses masking, not mod, for indexing a power-of-two-sized array,
-     * adds a release fence for publication, and possibly signals
-     * waiting workers to start scanning -- see below.)  Both a
-     * successful pop and poll mainly entail a CAS of a slot from
-     * non-null to null.
+     * properly fences accesses, and possibly signals waiting workers
+     * to start scanning -- see below.)  Both a successful pop and
+     * poll mainly entail a CAS of a slot from non-null to null.
      *
      * The pop operation (always performed by owner) is:
      *   if ((the task at top slot is not null) and
@@ -249,14 +230,10 @@
      *        (CAS slot to null))
      *           increment base and return task;
      *
-     * There are several variants of each of these. Most uses occur
-     * within operations that also interleave contention or emptiness
-     * tracking or inspection of elements before extracting them, so
-     * must interleave these with the above code. When performed by
-     * owner, getAndSet is used instead of CAS (see for example method
-     * nextLocalTask) which is usually more efficient, and possible
-     * because the top index cannot independently change during the
-     * operation.
+     * There are several variants of each of these; for example most
+     * versions of poll pre-screen the CAS by rechecking that the base
+     * has not changed since reading the slot, and most methods only
+     * attempt the CAS if base appears not to be equal to top.
      *
      * Memory ordering.  See "Correct and Efficient Work-Stealing for
      * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -265,37 +242,33 @@
      * algorithms similar to (but different than) the one used here.
      * Extracting tasks in array slots via (fully fenced) CAS provides
      * primary synchronization. The base and top indices imprecisely
-     * guide where to extract from. We do not usually require strict
-     * orderings of array and index updates. Many index accesses use
-     * plain mode, with ordering constrained by surrounding context
-     * (usually with respect to element CASes or the two WorkQueue
-     * volatile fields source and phase). When not otherwise already
-     * constrained, reads of "base" by queue owners use acquire-mode,
-     * and some externally callable methods preface accesses with
-     * acquire fences.  Additionally, to ensure that index update
-     * writes are not coalesced or postponed in loops etc, "opaque"
-     * mode is used in a few cases where timely writes are not
-     * otherwise ensured. The "locked" versions of push- and pop-
-     * based methods for shared queues differ from owned versions
-     * because locking already forces some of the ordering.
-     *
-     * Because indices and slot contents cannot always be consistent,
-     * a check that base == top indicates (momentary) emptiness, but
-     * otherwise may err on the side of possibly making the queue
-     * appear nonempty when a push, pop, or poll have not fully
-     * committed, or making it appear empty when an update of top has
-     * not yet been visibly written.  (Method isEmpty() checks the
-     * case of a partially completed removal of the last element.)
-     * Because of this, the poll operation, considered individually,
-     * is not wait-free. One thief cannot successfully continue until
-     * another in-progress one (or, if previously empty, a push)
-     * visibly completes.  This can stall threads when required to
-     * consume from a given queue (see method poll()).  However, in
-     * the aggregate, we ensure at least probabilistic
+     * guide where to extract from. We do not always require strict
+     * orderings of array and index updates, so sometimes let them be
+     * subject to compiler and processor reorderings. However, the
+     * volatile "base" index also serves as a basis for memory
+     * ordering: Slot accesses are preceded by a read of base,
+     * ensuring happens-before ordering with respect to stealers (so
+     * the slots themselves can be read via plain array reads.)  The
+     * only other memory orderings relied on are maintained in the
+     * course of signalling and activation (see below).  A check that
+     * base == top indicates (momentary) emptiness, but otherwise may
+     * err on the side of possibly making the queue appear nonempty
+     * when a push, pop, or poll have not fully committed, or making
+     * it appear empty when an update of top has not yet been visibly
+     * written.  (Method isEmpty() checks the case of a partially
+     * completed removal of the last element.)  Because of this, the
+     * poll operation, considered individually, is not wait-free. One
+     * thief cannot successfully continue until another in-progress
+     * one (or, if previously empty, a push) visibly completes.
+     * However, in the aggregate, we ensure at least probabilistic
      * non-blockingness.  If an attempted steal fails, a scanning
      * thief chooses a different random victim target to try next. So,
      * in order for one thief to progress, it suffices for any
-     * in-progress poll or new push on any empty queue to complete.
+     * in-progress poll or new push on any empty queue to
+     * complete. (This is why we normally use method pollAt and its
+     * variants that try once at the apparent base index, else
+     * consider alternative actions, rather than method poll, which
+     * retries.)
      *
      * This approach also enables support of a user mode in which
      * local task processing is in FIFO, not LIFO order, simply by
@@ -310,13 +283,16 @@
      * choosing existing queues, and may be randomly repositioned upon
      * contention with other submitters.  In essence, submitters act
      * like workers except that they are restricted to executing local
-     * tasks that they submitted.  Insertion of tasks in shared mode
-     * requires a lock but we use only a simple spinlock (using field
-     * phase), because submitters encountering a busy queue move to a
-     * different position to use or create other queues -- they block
-     * only when creating and registering new queues. Because it is
-     * used only as a spinlock, unlocking requires only a "releasing"
-     * store (using setRelease) unless otherwise signalling.
+     * tasks that they submitted (or in the case of CountedCompleters,
+     * others with the same root task).  Insertion of tasks in shared
+     * mode requires a lock but we use only a simple spinlock (using
+     * field qlock), because submitters encountering a busy queue move
+     * on to try or create other queues -- they block only when
+     * creating and registering new queues. Because it is used only as
+     * a spinlock, unlocking requires only a "releasing" store (using
+     * putOrderedInt).  The qlock is also used during termination
+     * detection, in which case it is forced to a negative
+     * non-lockable value.
      *
      * Management
      * ==========
@@ -330,36 +306,43 @@
      * There are only a few properties that we can globally track or
      * maintain, so we pack them into a small number of variables,
      * often maintaining atomicity without blocking or locking.
-     * Nearly all essentially atomic control state is held in a few
+     * Nearly all essentially atomic control state is held in two
      * volatile variables that are by far most often read (not
-     * written) as status and consistency checks. We pack as much
-     * information into them as we can.
+     * written) as status and consistency checks. (Also, field
+     * "config" holds unchanging configuration state.)
      *
      * Field "ctl" contains 64 bits holding information needed to
-     * atomically decide to add, enqueue (on an event queue), and
-     * dequeue and release workers.  To enable this packing, we
-     * restrict maximum parallelism to (1<<15)-1 (which is far in
-     * excess of normal operating range) to allow ids, counts, and
-     * their negations (used for thresholding) to fit into 16bit
+     * atomically decide to add, inactivate, enqueue (on an event
+     * queue), dequeue, and/or re-activate workers.  To enable this
+     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
+     * far in excess of normal operating range) to allow ids, counts,
+     * and their negations (used for thresholding) to fit into 16bit
      * subfields.
      *
-     * Field "mode" holds configuration parameters as well as lifetime
-     * status, atomically and monotonically setting SHUTDOWN, STOP,
-     * and finally TERMINATED bits.
+     * Field "runState" holds lifetime status, atomically and
+     * monotonically setting STARTED, SHUTDOWN, STOP, and finally
+     * TERMINATED bits.
+     *
+     * Field "auxState" is a ReentrantLock subclass that also
+     * opportunistically holds some other bookkeeping fields accessed
+     * only when locked.  It is mainly used to lock (infrequent)
+     * updates to workQueues.  The auxState instance is itself lazily
+     * constructed (see tryInitialize), requiring a double-check-style
+     * bootstrapping use of field runState, and locking a private
+     * static.
      *
      * Field "workQueues" holds references to WorkQueues.  It is
-     * updated (only during worker creation and termination) under
-     * lock (using field workerNamePrefix as lock), but is otherwise
-     * concurrently readable, and accessed directly. We also ensure
-     * that uses of the array reference itself never become too stale
-     * in case of resizing, by arranging that (re-)reads are separated
-     * by at least one acquiring read access.  To simplify index-based
-     * operations, the array size is always a power of two, and all
-     * readers must tolerate null slots. Worker queues are at odd
-     * indices. Shared (submission) queues are at even indices, up to
-     * a maximum of 64 slots, to limit growth even if the array needs
-     * to expand to add more workers. Grouping them together in this
-     * way simplifies and speeds up task scanning.
+     * updated (only during worker creation and termination) under the
+     * lock, but is otherwise concurrently readable, and accessed
+     * directly. We also ensure that reads of the array reference
+     * itself never become too stale (for example, re-reading before
+     * each scan). To simplify index-based operations, the array size
+     * is always a power of two, and all readers must tolerate null
+     * slots. Worker queues are at odd indices. Shared (submission)
+     * queues are at even indices, up to a maximum of 64 slots, to
+     * limit growth even if array needs to expand to add more
+     * workers. Grouping them together in this way simplifies and
+     * speeds up task scanning.
      *
      * All worker thread creation is on-demand, triggered by task
      * submissions, replacement of terminated workers, and/or
@@ -378,37 +361,30 @@
      * workers unless there appear to be tasks available.  On the
      * other hand, we must quickly prod them into action when new
      * tasks are submitted or generated. In many usages, ramp-up time
-     * is the main limiting factor in overall performance, which is
-     * compounded at program start-up by JIT compilation and
-     * allocation. So we streamline this as much as possible.
+     * to activate workers is the main limiting factor in overall
+     * performance, which is compounded at program start-up by JIT
+     * compilation and allocation. So we streamline this as much as
+     * possible.
      *
-     * The "ctl" field atomically maintains total worker and
-     * "released" worker counts, plus the head of the available worker
-     * queue (actually stack, represented by the lower 32bit subfield
-     * of ctl).  Released workers are those known to be scanning for
-     * and/or running tasks. Unreleased ("available") workers are
-     * recorded in the ctl stack. These workers are made available for
-     * signalling by enqueuing in ctl (see method runWorker).  The
-     * "queue" is a form of Treiber stack. This is ideal for
-     * activating threads in most-recently used order, and improves
+     * The "ctl" field atomically maintains active and total worker
+     * counts as well as a queue to place waiting threads so they can
+     * be located for signalling. Active counts also play the role of
+     * quiescence indicators, so are decremented when workers believe
+     * that there are no more tasks to execute. The "queue" is
+     * actually a form of Treiber stack.  A stack is ideal for
+     * activating threads in most-recently used order. This improves
      * performance and locality, outweighing the disadvantages of
      * being prone to contention and inability to release a worker
-     * unless it is topmost on stack.  To avoid missed signal problems
-     * inherent in any wait/signal design, available workers rescan
-     * for (and if found run) tasks after enqueuing.  Normally their
-     * release status will be updated while doing so, but the released
-     * worker ctl count may underestimate the number of active
-     * threads. (However, it is still possible to determine quiescence
-     * via a validation traversal -- see isQuiescent).  After an
-     * unsuccessful rescan, available workers are blocked until
-     * signalled (see signalWork).  The top stack state holds the
-     * value of the "phase" field of the worker: its index and status,
-     * plus a version counter that, in addition to the count subfields
-     * (also serving as version stamps) provide protection against
-     * Treiber stack ABA effects.
+     * unless it is topmost on stack.  We block/unblock workers after
+     * pushing on the idle worker stack (represented by the lower
+     * 32bit subfield of ctl) when they cannot find work.  The top
+     * stack state holds the value of the "scanState" field of the
+     * worker: its index and status, plus a version counter that, in
+     * addition to the count subfields (also serving as version
+     * stamps) provide protection against Treiber stack ABA effects.
      *
-     * Creating workers. To create a worker, we pre-increment counts
-     * (serving as a reservation), and attempt to construct a
+     * Creating workers. To create a worker, we pre-increment total
+     * count (serving as a reservation), and attempt to construct a
      * ForkJoinWorkerThread via its factory. Upon construction, the
      * new thread invokes registerWorker, where it constructs a
      * WorkQueue and is assigned an index in the workQueues array
@@ -430,14 +406,15 @@
      * submission queues for existing external threads (see
      * externalPush).
      *
-     * WorkQueue field "phase" is used by both workers and the pool to
-     * manage and track whether a worker is UNSIGNALLED (possibly
-     * blocked waiting for a signal).  When a worker is enqueued its
-     * phase field is set. Note that phase field updates lag queue CAS
-     * releases so usage requires care -- seeing a negative phase does
-     * not guarantee that the worker is available. When queued, the
-     * lower 16 bits of scanState must hold its pool index. So we
-     * place the index there upon initialization and otherwise keep it
+     * WorkQueue field scanState is used by both workers and the pool
+     * to manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is inactivated,
+     * its scanState field is set, and is prevented from executing
+     * tasks, even though it must scan once for them to avoid queuing
+     * races. Note that scanState updates lag queue CAS releases so
+     * usage requires care. When queued, the lower 16 bits of
+     * scanState must hold its pool index. So we place the index there
+     * upon initialization (see registerWorker) and otherwise keep it
      * there or restore it when necessary.
      *
      * The ctl field also serves as the basis for memory
@@ -446,68 +423,85 @@
      * consumers sync with each other by both writing/CASing ctl (even
      * if to its current value).  This would be extremely costly. So
      * we relax it in several ways: (1) Producers only signal when
-     * their queue is possibly empty at some point during a push
-     * operation (which requires conservatively checking size zero or
-     * one to cover races). (2) Other workers propagate this signal
-     * when they find tasks in a queue with size greater than one. (3)
-     * Workers only enqueue after scanning (see below) and not finding
-     * any tasks.  (4) Rather than CASing ctl to its current value in
-     * the common case where no action is required, we reduce write
-     * contention by equivalently prefacing signalWork when called by
-     * an external task producer using a memory access with
-     * full-volatile semantics or a "fullFence".
+     * their queue is empty. Other workers propagate this signal (in
+     * method scan) when they find tasks. (2) Workers only enqueue
+     * after scanning (see below) and not finding any tasks.  (3)
+     * Rather than CASing ctl to its current value in the common case
+     * where no action is required, we reduce write contention by
+     * equivalently prefacing signalWork when called by an external
+     * task producer using a memory access with full-volatile
+     * semantics or a "fullFence". (4) For internal task producers we
+     * rely on the fact that even if no other workers awaken, the
+     * producer itself will eventually see the task and execute it.
      *
-     * Almost always, too many signals are issued, in part because a
-     * task producer cannot tell if some existing worker is in the
-     * midst of finishing one task (or already scanning) and ready to
-     * take another without being signalled. So the producer might
-     * instead activate a different worker that does not find any
-     * work, and then inactivates. This scarcely matters in
-     * steady-state computations involving all workers, but can create
-     * contention and bookkeeping bottlenecks during ramp-up,
-     * ramp-down, and small computations involving only a few workers.
+     * Almost always, too many signals are issued. A task producer
+     * cannot in general tell if some existing worker is in the midst
+     * of finishing one task (or already scanning) and ready to take
+     * another without being signalled. So the producer might instead
+     * activate a different worker that does not find any work, and
+     * then inactivates. This scarcely matters in steady-state
+     * computations involving all workers, but can create contention
+     * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
+     * computations involving only a few workers.
      *
-     * Scanning. Method scan (from runWorker) performs top-level
-     * scanning for tasks. (Similar scans appear in helpQuiesce and
-     * pollScan.)  Each scan traverses and tries to poll from each
-     * queue starting at a random index. Scans are not performed in
-     * ideal random permutation order, to reduce cacheline
-     * contention. The pseudorandom generator need not have
-     * high-quality statistical properties in the long term, but just
-     * within computations; We use Marsaglia XorShifts (often via
-     * ThreadLocalRandom.nextSecondarySeed), which are cheap and
-     * suffice. Scanning also includes contention reduction: When
-     * scanning workers fail to extract an apparently existing task,
-     * they soon restart at a different pseudorandom index.  This form
-     * of backoff improves throughput when many threads are trying to
-     * take tasks from few queues, which can be common in some usages.
-     * Scans do not otherwise explicitly take into account core
-     * affinities, loads, cache localities, etc, However, they do
-     * exploit temporal locality (which usually approximates these) by
-     * preferring to re-poll from the same queue after a successful
-     * poll before trying others (see method topLevelExec). However
-     * this preference is bounded (see TOP_BOUND_SHIFT) as a safeguard
-     * against infinitely unfair looping under unbounded user task
-     * recursion, and also to reduce long-term contention when many
-     * threads poll few queues holding many small tasks. The bound is
-     * high enough to avoid much impact on locality and scheduling
-     * overhead.
+     * Scanning. Method scan() performs top-level scanning for tasks.
+     * Each scan traverses (and tries to poll from) each queue in
+     * pseudorandom permutation order by randomly selecting an origin
+     * index and a step value.  (The pseudorandom generator need not
+     * have high-quality statistical properties in the long term, but
+     * just within computations; We use 64bit and 32bit Marsaglia
+     * XorShifts, which are cheap and suffice here.)  Scanning also
+     * employs contention reduction: When scanning workers fail a CAS
+     * polling for work, they soon restart with a different
+     * pseudorandom scan order (thus likely retrying at different
+     * intervals). This improves throughput when many threads are
+     * trying to take tasks from few queues.  Scans do not otherwise
+     * explicitly take into account core affinities, loads, cache
+     * localities, etc, However, they do exploit temporal locality
+     * (which usually approximates these) by preferring to re-poll (up
+     * to POLL_LIMIT times) from the same queue after a successful
+     * poll before trying others.  Restricted forms of scanning occur
+     * in methods helpComplete and findNonEmptyStealQueue, and take
+     * similar but simpler forms.
+     *
+     * Deactivation and waiting. Queuing encounters several intrinsic
+     * races; most notably that an inactivating scanning worker can
+     * miss seeing a task produced during a scan.  So when a worker
+     * cannot find a task to steal, it inactivates and enqueues, and
+     * then rescans to ensure that it didn't miss one, reactivating
+     * upon seeing one with probability approximately proportional to
+     * probability of a miss.  (In most cases, the worker will be
+     * signalled before self-signalling, avoiding cascades of multiple
+     * signals for the same task).
+     *
+     * Workers block (in method awaitWork) using park/unpark;
+     * advertising the need for signallers to unpark by setting their
+     * "parker" fields.
      *
      * Trimming workers. To release resources after periods of lack of
      * use, a worker starting to wait when the pool is quiescent will
-     * time out and terminate (see method runWorker) if the pool has
-     * remained quiescent for period given by field keepAlive.
+     * time out and terminate (see awaitWork) if the pool has remained
+     * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
+     * period as the number of threads decreases, eventually removing
+     * all workers.
      *
      * Shutdown and Termination. A call to shutdownNow invokes
      * tryTerminate to atomically set a runState bit. The calling
      * thread, as well as every other worker thereafter terminating,
-     * helps terminate others by cancelling their unprocessed tasks,
-     * and waking them up, doing so repeatedly until stable. Calls to
-     * non-abrupt shutdown() preface this by checking whether
-     * termination should commence by sweeping through queues (until
-     * stable) to ensure lack of in-flight submissions and workers
-     * about to process them before triggering the "STOP" phase of
-     * termination.
+     * helps terminate others by setting their (qlock) status,
+     * cancelling their unprocessed tasks, and waking them up, doing
+     * so repeatedly until stable. Calls to non-abrupt shutdown()
+     * preface this by checking whether termination should commence.
+     * This relies primarily on the active count bits of "ctl"
+     * maintaining consensus -- tryTerminate is called from awaitWork
+     * whenever quiescent. However, external submitters do not take
+     * part in this consensus.  So, tryTerminate sweeps through queues
+     * (until stable) to ensure lack of in-flight submissions and
+     * workers about to process them before triggering the "STOP"
+     * phase of termination. (Note: there is an intrinsic conflict if
+     * helpQuiescePool is called when shutdown is enabled. Both wait
+     * for quiescence, but tryTerminate is biased to not trigger until
+     * helpQuiescePool completes.)
      *
      * Joining Tasks
      * =============
@@ -515,12 +509,12 @@
      * Any of several actions may be taken when one worker is waiting
      * to join a task stolen (or always held) by another.  Because we
      * are multiplexing many tasks on to a pool of workers, we can't
-     * always just let them block (as in Thread.join).  We also cannot
-     * just reassign the joiner's run-time stack with another and
-     * replace it later, which would be a form of "continuation", that
-     * even if possible is not necessarily a good idea since we may
-     * need both an unblocked task and its continuation to progress.
-     * Instead we combine two tactics:
+     * just let them block (as in Thread.join).  We also cannot just
+     * reassign the joiner's run-time stack with another and replace
+     * it later, which would be a form of "continuation", that even if
+     * possible is not necessarily a good idea since we may need both
+     * an unblocked task and its continuation to progress.  Instead we
+     * combine two tactics:
      *
      *   Helping: Arranging for the joiner to execute some task that it
      *      would be running if the steal had not occurred.
@@ -533,44 +527,79 @@
      * helping a hypothetical compensator: If we can readily tell that
      * a possible action of a compensator is to steal and execute the
      * task being joined, the joining thread can do so directly,
-     * without the need for a compensation thread.
+     * without the need for a compensation thread (although at the
+     * expense of larger run-time stacks, but the tradeoff is
+     * typically worthwhile).
      *
      * The ManagedBlocker extension API can't use helping so relies
      * only on compensation in method awaitBlocker.
      *
-     * The algorithm in awaitJoin entails a form of "linear helping".
-     * Each worker records (in field source) the id of the queue from
-     * which it last stole a task.  The scan in method awaitJoin uses
-     * these markers to try to find a worker to help (i.e., steal back
-     * a task from and execute it) that could hasten completion of the
-     * actively joined task.  Thus, the joiner executes a task that
-     * would be on its own local deque if the to-be-joined task had
-     * not been stolen. This is a conservative variant of the approach
-     * described in Wagner & Calder "Leapfrogging: a portable
-     * technique for implementing efficient futures" SIGPLAN Notices,
-     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
-     * mainly in that we only record queue ids, not full dependency
-     * links.  This requires a linear scan of the workQueues array to
-     * locate stealers, but isolates cost to when it is needed, rather
-     * than adding to per-task overhead. Searches can fail to locate
-     * stealers GC stalls and the like delay recording sources.
-     * Further, even when accurately identified, stealers might not
-     * ever produce a task that the joiner can in turn help with. So,
-     * compensation is tried upon failure to find tasks to run.
+     * The algorithm in helpStealer entails a form of "linear
+     * helping".  Each worker records (in field currentSteal) the most
+     * recent task it stole from some other worker (or a submission).
+     * It also records (in field currentJoin) the task it is currently
+     * actively joining. Method helpStealer uses these markers to try
+     * to find a worker to help (i.e., steal back a task from and
+     * execute it) that could hasten completion of the actively joined
+     * task.  Thus, the joiner executes a task that would be on its
+     * own local deque had the to-be-joined task not been stolen. This
+     * is a conservative variant of the approach described in Wagner &
+     * Calder "Leapfrogging: a portable technique for implementing
+     * efficient futures" SIGPLAN Notices, 1993
+     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
+     * that: (1) We only maintain dependency links across workers upon
+     * steals, rather than use per-task bookkeeping.  This sometimes
+     * requires a linear scan of workQueues array to locate stealers,
+     * but often doesn't because stealers leave hints (that may become
+     * stale/wrong) of where to locate them.  It is only a hint
+     * because a worker might have had multiple steals and the hint
+     * records only one of them (usually the most current).  Hinting
+     * isolates cost to when it is needed, rather than adding to
+     * per-task overhead.  (2) It is "shallow", ignoring nesting and
+     * potentially cyclic mutual steals.  (3) It is intentionally
+     * racy: field currentJoin is updated only while actively joining,
+     * which means that we miss links in the chain during long-lived
+     * tasks, GC stalls etc (which is OK since blocking in such cases
+     * is usually a good idea).  (4) We bound the number of attempts
+     * to find work using checksums and fall back to suspending the
+     * worker and if necessary replacing it with another.
      *
-     * Compensation does not by default aim to keep exactly the target
+     * Helping actions for CountedCompleters do not require tracking
+     * currentJoins: Method helpComplete takes and executes any task
+     * with the same root as the task being waited on (preferring
+     * local pops to non-local polls). However, this still entails
+     * some traversal of completer chains, so is less efficient than
+     * using CountedCompleters without explicit joins.
+     *
+     * Compensation does not aim to keep exactly the target
      * parallelism number of unblocked threads running at any given
      * time. Some previous versions of this class employed immediate
      * compensations for any blocked join. However, in practice, the
      * vast majority of blockages are transient byproducts of GC and
-     * other JVM or OS activities that are made worse by replacement
-     * when they cause longer-term oversubscription.  Rather than
-     * impose arbitrary policies, we allow users to override the
-     * default of only adding threads upon apparent starvation.  The
-     * compensation mechanism may also be bounded.  Bounds for the
+     * other JVM or OS activities that are made worse by replacement.
+     * Currently, compensation is attempted only after validating that
+     * all purportedly active threads are processing tasks by checking
+     * field WorkQueue.scanState, which eliminates most false
+     * positives.  Also, compensation is bypassed (tolerating fewer
+     * threads) in the most common case in which it is rarely
+     * beneficial: when a worker with an empty queue (thus no
+     * continuation tasks) blocks on a join and there still remain
+     * enough threads to ensure liveness.
+     *
+     * Spare threads are removed as soon as they notice that the
+     * target parallelism level has been exceeded, in method
+     * tryDropSpare. (Method scan arranges returns for rechecks upon
+     * each probe via the "bound" parameter.)
+     *
+     * The compensation mechanism may be bounded.  Bounds for the
      * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
      * with programming errors and abuse before running out of
-     * resources to do so.
+     * resources to do so. In other cases, users may supply factories
+     * that limit thread construction. The effects of bounding in this
+     * pool (like all others) is imprecise.  Total worker counts are
+     * decremented when threads deregister, not when they exit and
+     * resources are reclaimed by the JVM and OS. So the number of
+     * simultaneously live threads may transiently exceed bounds.
      *
      * Common Pool
      * ===========
@@ -578,7 +607,9 @@
      * The static common pool always exists after static
      * initialization.  Since it (or any other created pool) need
      * never be used, we minimize initial construction overhead and
-     * footprint to the setup of about a dozen fields.
+     * footprint to the setup of about a dozen fields, with no nested
+     * allocation. Most bootstrapping occurs within method
+     * externalSubmit during the first submission to the pool.
      *
      * When external threads submit to the common pool, they can
      * perform subtask processing (see externalHelpComplete and
@@ -598,39 +629,31 @@
      * InnocuousForkJoinWorkerThread when there is a SecurityManager
      * present. These workers have no permissions set, do not belong
      * to any user-defined ThreadGroup, and erase all ThreadLocals
-     * after executing any top-level task (see
-     * WorkQueue.afterTopLevelExec).  The associated mechanics (mainly
-     * in ForkJoinWorkerThread) may be JVM-dependent and must access
-     * particular Thread class fields to achieve this effect.
-     *
-     * Memory placement
-     * ================
-     *
-     * Performance can be very sensitive to placement of instances of
-     * ForkJoinPool and WorkQueues and their queue arrays. To reduce
-     * false-sharing impact, the @Contended annotation isolates
-     * adjacent WorkQueue instances, as well as the ForkJoinPool.ctl
-     * field. WorkQueue arrays are allocated (by their threads) with
-     * larger initial sizes than most ever need, mostly to reduce
-     * false sharing with current garbage collectors that use cardmark
-     * tables.
+     * after executing any top-level task (see WorkQueue.runTask).
+     * The associated mechanics (mainly in ForkJoinWorkerThread) may
+     * be JVM-dependent and must access particular Thread class fields
+     * to achieve this effect.
      *
      * Style notes
      * ===========
      *
-     * Memory ordering relies mainly on VarHandles.  This can be
-     * awkward and ugly, but also reflects the need to control
+     * Memory ordering relies mainly on Unsafe intrinsics that carry
+     * the further responsibility of explicitly performing null- and
+     * bounds- checks otherwise carried out implicitly by JVMs.  This
+     * can be awkward and ugly, but also reflects the need to control
      * outcomes across the unusual cases that arise in very racy code
-     * with very few invariants. All fields are read into locals
-     * before use, and null-checked if they are references.  Array
-     * accesses using masked indices include checks (that are always
-     * true) that the array length is non-zero to avoid compilers
-     * inserting more expensive traps.  This is usually done in a
-     * "C"-like style of listing declarations at the heads of methods
-     * or blocks, and using inline assignments on first encounter.
-     * Nearly all explicit checks lead to bypass/return, not exception
-     * throws, because they may legitimately arise due to
-     * cancellation/revocation during shutdown.
+     * with very few invariants. So these explicit checks would exist
+     * in some form anyway.  All fields are read into locals before
+     * use, and null-checked if they are references.  This is usually
+     * done in a "C"-like style of listing declarations at the heads
+     * of methods or blocks, and using inline assignments on first
+     * encounter.  Array bounds-checks are usually performed by
+     * masking with array.length-1, which relies on the invariant that
+     * these arrays are created with positive lengths, which is itself
+     * paranoically checked. Nearly all explicit checks lead to
+     * bypass/return, not exception throws, because they may
+     * legitimately arise due to cancellation/revocation during
+     * shutdown.
      *
      * There is a lot of representation-level coupling among classes
      * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
@@ -640,11 +663,10 @@
      * representations will need to be accompanied by algorithmic
      * changes anyway. Several methods intrinsically sprawl because
      * they must accumulate sets of consistent reads of fields held in
-     * local variables. Some others are artificially broken up to
-     * reduce producer/consumer imbalances due to dynamic compilation.
-     * There are also other coding oddities (including several
-     * unnecessary-looking hoisted null checks) that help some methods
-     * perform reasonably even when interpreted (not compiled).
+     * local variables.  There are also other coding oddities
+     * (including several unnecessary-looking hoisted null checks)
+     * that help some methods perform reasonably even when interpreted
+     * (not compiled).
      *
      * The order of declarations in this file is (with a few exceptions):
      * (1) Static utility functions
@@ -680,13 +702,6 @@
     public static interface ForkJoinWorkerThreadFactory {
         /**
          * Returns a new worker thread operating in the given pool.
-         * Returning null or throwing an exception may result in tasks
-         * never being executed.  If this method throws an exception,
-         * it is relayed to the caller of the method (for example
-         * {@code execute}) causing attempted thread creation. If this
-         * method returns null or throws an exception, it is not
-         * retried until the next attempted creation (for example
-         * another call to {@code execute}).
          *
          * @param pool the pool this thread works in
          * @return the new worker thread, or {@code null} if the request
@@ -696,98 +711,120 @@
         public ForkJoinWorkerThread newThread(ForkJoinPool pool);
     }
 
-    static AccessControlContext contextWithPermissions(Permission ... perms) {
-        Permissions permissions = new Permissions();
-        for (Permission perm : perms)
-            permissions.add(perm);
-        return new AccessControlContext(
-            new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
-    }
-
     /**
      * Default ForkJoinWorkerThreadFactory implementation; creates a
-     * new ForkJoinWorkerThread using the system class loader as the
-     * thread context class loader.
+     * new ForkJoinWorkerThread.
      */
     private static final class DefaultForkJoinWorkerThreadFactory
         implements ForkJoinWorkerThreadFactory {
-        private static final AccessControlContext ACC = contextWithPermissions(
-            new RuntimePermission("getClassLoader"),
-            new RuntimePermission("setContextClassLoader"));
-
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return AccessController.doPrivileged(
-                new PrivilegedAction<>() {
-                    public ForkJoinWorkerThread run() {
-                        return new ForkJoinWorkerThread(
-                            pool, ClassLoader.getSystemClassLoader()); }},
-                ACC);
+            return new ForkJoinWorkerThread(pool);
         }
     }
 
+    /**
+     * Class for artificial tasks that are used to replace the target
+     * of local joins if they are removed from an interior queue slot
+     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
+     * actually do anything beyond having a unique identity.
+     */
+    private static final class EmptyTask extends ForkJoinTask<Void> {
+        private static final long serialVersionUID = -7721805057305804111L;
+        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void x) {}
+        public final boolean exec() { return true; }
+    }
+
+    /**
+     * Additional fields and lock created upon initialization.
+     */
+    private static final class AuxState extends ReentrantLock {
+        private static final long serialVersionUID = -6001602636862214147L;
+        volatile long stealCount;     // cumulative steal count
+        long indexSeed;               // index bits for registerWorker
+        AuxState() {}
+    }
+
     // Constants shared across ForkJoinPool and WorkQueue
 
     // Bounds
-    static final int SWIDTH       = 16;            // width of short
     static final int SMASK        = 0xffff;        // short bits == max index
     static final int MAX_CAP      = 0x7fff;        // max #workers - 1
+    static final int EVENMASK     = 0xfffe;        // even short bits
     static final int SQMASK       = 0x007e;        // max 64 (even) slots
 
-    // Masks and units for WorkQueue.phase and ctl sp subfield
+    // Masks and units for WorkQueue.scanState and ctl sp subfield
     static final int UNSIGNALLED  = 1 << 31;       // must be negative
     static final int SS_SEQ       = 1 << 16;       // version count
-    static final int QLOCK        = 1;             // must be 1
 
-    // Mode bits and sentinels, some also used in WorkQueue id and.source fields
-    static final int OWNED        = 1;             // queue has owner thread
-    static final int FIFO         = 1 << 16;       // fifo queue or access mode
-    static final int SHUTDOWN     = 1 << 18;
-    static final int TERMINATED   = 1 << 19;
-    static final int STOP         = 1 << 31;       // must be negative
-    static final int QUIET        = 1 << 30;       // not scanning or working
-    static final int DORMANT      = QUIET | UNSIGNALLED;
+    // Mode bits for ForkJoinPool.config and WorkQueue.config
+    static final int MODE_MASK    = 0xffff << 16;  // top half of int
+    static final int SPARE_WORKER = 1 << 17;       // set if tc > 0 on creation
+    static final int UNREGISTERED = 1 << 18;       // to skip some of deregister
+    static final int FIFO_QUEUE   = 1 << 31;       // must be negative
+    static final int LIFO_QUEUE   = 0;             // for clarity
+    static final int IS_OWNED     = 1;             // low bit 0 if shared
 
     /**
-     * Initial capacity of work-stealing queue array.
-     * Must be a power of two, at least 2.
+     * The maximum number of task executions from the same queue
+     * before checking other queues, bounding unfairness and impact of
+     * infinite user task recursion.  Must be a power of two minus 1.
      */
-    static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
-    /**
-     * Maximum capacity for queue arrays. Must be a power of two less
-     * than or equal to 1 << (31 - width of array entry) to ensure
-     * lack of wraparound of index calculations, but defined to a
-     * value a bit less than this to help users trap runaway programs
-     * before saturating systems.
-     */
-    static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
-
-    /**
-     * The maximum number of top-level polls per worker before
-     * checking other queues, expressed as a bit shift to, in effect,
-     * multiply by pool size, and then use as random value mask, so
-     * average bound is about poolSize*(1<<TOP_BOUND_SHIFT).  See
-     * above for rationale.
-     */
-    static final int TOP_BOUND_SHIFT = 10;
+    static final int POLL_LIMIT = (1 << 10) - 1;
 
     /**
      * Queues supporting work-stealing as well as external task
      * submission. See above for descriptions and algorithms.
+     * Performance on most platforms is very sensitive to placement of
+     * instances of both WorkQueues and their arrays -- we absolutely
+     * do not want multiple WorkQueue instances or multiple queue
+     * arrays sharing cache lines. The @Contended annotation alerts
+     * JVMs to try to keep instances apart.
      */
     // Android-removed: @Contended, this hint is not used by the Android runtime.
     //@jdk.internal.vm.annotation.Contended
     static final class WorkQueue {
-        volatile int source;       // source queue id, or sentinel
-        int id;                    // pool index, mode, tag
-        int base;                  // index of next slot for poll
-        int top;                   // index of next slot for push
-        volatile int phase;        // versioned, negative: queued, 1: locked
-        int stackPred;             // pool stack (ctl) predecessor link
+
+        /**
+         * Capacity of work-stealing queue array upon initialization.
+         * Must be a power of two; at least 4, but should be larger to
+         * reduce or eliminate cacheline sharing among queues.
+         * Currently, it is much larger, as a partial workaround for
+         * the fact that JVMs often place arrays in locations that
+         * share GC bookkeeping (especially cardmarks) such that
+         * per-write accesses encounter serious memory contention.
+         */
+        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+        /**
+         * Maximum size for queue arrays. Must be a power of two less
+         * than or equal to 1 << (31 - width of array entry) to ensure
+         * lack of wraparound of index calculations, but defined to a
+         * value a bit less than this to help users trap runaway
+         * programs before saturating systems.
+         */
+        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+        // Instance fields
+
+        volatile int scanState;    // versioned, negative if inactive
+        int stackPred;             // pool stack (ctl) predecessor
         int nsteals;               // number of steals
-        ForkJoinTask<?>[] array;   // the queued tasks; power of 2 size
+        int hint;                  // randomization and stealer index hint
+        int config;                // pool index and mode
+        volatile int qlock;        // 1: locked, < 0: terminate; else 0
+        volatile int base;         // index of next slot for poll
+        int top;                   // index of next slot for push
+        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
         final ForkJoinPool pool;   // the containing pool (may be null)
         final ForkJoinWorkerThread owner; // owning thread or null if shared
+        volatile Thread parker;    // == owner during call to park; else null
+        volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
+
+      // Android-removed: @Contended, this hint is not used by the Android runtime.
+      // @jdk.internal.vm.annotation.Contended("group2") // segregate
+        volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
 
         WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
             this.pool = pool;
@@ -797,28 +834,17 @@
         }
 
         /**
-         * Tries to lock shared queue by CASing phase field.
-         */
-        final boolean tryLockPhase() {
-            return PHASE.compareAndSet(this, 0, 1);
-        }
-
-        final void releasePhaseLock() {
-            PHASE.setRelease(this, 0);
-        }
-
-        /**
          * Returns an exportable index (used by ForkJoinWorkerThread).
          */
         final int getPoolIndex() {
-            return (id & 0xffff) >>> 1; // ignore odd/even tag bit
+            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
         }
 
         /**
          * Returns the approximate number of tasks in the queue.
          */
         final int queueSize() {
-            int n = (int)BASE.getAcquire(this) - top;
+            int n = base - top;       // read base first
             return (n >= 0) ? 0 : -n; // ignore transient negative
         }
 
@@ -828,12 +854,11 @@
          * near-empty queue has at least one unclaimed task.
          */
         final boolean isEmpty() {
-            ForkJoinTask<?>[] a; int n, cap, b;
-            VarHandle.acquireFence(); // needed by external callers
-            return ((n = (b = base) - top) >= 0 || // possibly one task
+            ForkJoinTask<?>[] a; int n, al, s;
+            return ((n = base - (s = top)) >= 0 || // possibly one task
                     (n == -1 && ((a = array) == null ||
-                                 (cap = a.length) == 0 ||
-                                 a[(cap - 1) & b] == null)));
+                                 (al = a.length) == 0 ||
+                                 a[(al - 1) & (s - 1)] == null)));
         }
 
         /**
@@ -843,99 +868,116 @@
          * @throws RejectedExecutionException if array cannot be resized
          */
         final void push(ForkJoinTask<?> task) {
-            ForkJoinTask<?>[] a;
-            int s = top, d, cap, m;
-            ForkJoinPool p = pool;
-            if ((a = array) != null && (cap = a.length) > 0) {
-                QA.setRelease(a, (m = cap - 1) & s, task);
+            U.storeFence();              // ensure safe publication
+            int s = top, al, d; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                a[(al - 1) & s] = task;  // relaxed writes OK
                 top = s + 1;
-                if (((d = s - (int)BASE.getAcquire(this)) & ~1) == 0 &&
-                    p != null) {                 // size 0 or 1
-                    VarHandle.fullFence();
+                ForkJoinPool p = pool;
+                if ((d = base - s) == 0 && p != null) {
+                    U.fullFence();
                     p.signalWork();
                 }
-                else if (d == m)
-                    growArray(false);
+                else if (al + d == 1)
+                    growArray();
             }
         }
 
         /**
-         * Version of push for shared queues. Call only with phase lock held.
-         * @return true if should signal work
+         * Initializes or doubles the capacity of array. Call either
+         * by owner or with lock held -- it is OK for base, but not
+         * top, to move while resizings are in progress.
          */
-        final boolean lockedPush(ForkJoinTask<?> task) {
-            ForkJoinTask<?>[] a;
-            boolean signal = false;
-            int s = top, b = base, cap, d;
-            if ((a = array) != null && (cap = a.length) > 0) {
-                a[(cap - 1) & s] = task;
-                top = s + 1;
-                if (b - s + cap - 1 == 0)
-                    growArray(true);
-                else {
-                    phase = 0; // full volatile unlock
-                    if (((s - base) & ~1) == 0) // size 0 or 1
-                        signal = true;
-                }
-            }
-            return signal;
-        }
-
-        /**
-         * Doubles the capacity of array. Call either by owner or with
-         * lock held -- it is OK for base, but not top, to move while
-         * resizings are in progress.
-         */
-        final void growArray(boolean locked) {
-            ForkJoinTask<?>[] newA = null;
-            try {
-                ForkJoinTask<?>[] oldA; int oldSize, newSize;
-                if ((oldA = array) != null && (oldSize = oldA.length) > 0 &&
-                    (newSize = oldSize << 1) <= MAXIMUM_QUEUE_CAPACITY &&
-                    newSize > 0) {
-                    try {
-                        newA = new ForkJoinTask<?>[newSize];
-                    } catch (OutOfMemoryError ex) {
-                    }
-                    if (newA != null) { // poll from old array, push to new
-                        int oldMask = oldSize - 1, newMask = newSize - 1;
-                        for (int s = top - 1, k = oldMask; k >= 0; --k) {
-                            ForkJoinTask<?> x = (ForkJoinTask<?>)
-                                QA.getAndSet(oldA, s & oldMask, null);
-                            if (x != null)
-                                newA[s-- & newMask] = x;
-                            else
-                                break;
-                        }
-                        array = newA;
-                        VarHandle.releaseFence();
-                    }
-                }
-            } finally {
-                if (locked)
-                    phase = 0;
-            }
-            if (newA == null)
+        final ForkJoinTask<?>[] growArray() {
+            ForkJoinTask<?>[] oldA = array;
+            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
+            if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
                 throw new RejectedExecutionException("Queue capacity exceeded");
+            int oldMask, t, b;
+            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
+            if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
+                (t = top) - (b = base) > 0) {
+                int mask = size - 1;
+                do { // emulate poll from old array, push to new array
+                    int index = b & oldMask;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> x = (ForkJoinTask<?>)
+                        U.getObjectVolatile(oldA, offset);
+                    if (x != null &&
+                        U.compareAndSwapObject(oldA, offset, x, null))
+                        a[b & mask] = x;
+                } while (++b != t);
+                U.storeFence();
+            }
+            return a;
+        }
+
+        /**
+         * Takes next task, if one exists, in LIFO order.  Call only
+         * by owner in unshared queues.
+         */
+        final ForkJoinTask<?> pop() {
+            int b = base, s = top, al, i; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObject(a, offset);
+                if (t != null &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    top = s;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes a task in FIFO order if b is base of queue and a task
+         * can be claimed without contention. Specialized versions
+         * appear in ForkJoinPool methods scan and helpStealer.
+         */
+        final ForkJoinTask<?> pollAt(int b) {
+            ForkJoinTask<?>[] a; int al;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (t != null && b++ == base &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    base = b;
+                    return t;
+                }
+            }
+            return null;
         }
 
         /**
          * Takes next task, if one exists, in FIFO order.
          */
         final ForkJoinTask<?> poll() {
-            int b, k, cap; ForkJoinTask<?>[] a;
-            while ((a = array) != null && (cap = a.length) > 0 &&
-                   top - (b = base) > 0) {
-                ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    QA.getAcquire(a, k = (cap - 1) & b);
-                if (base == b++) {
-                    if (t == null)
-                        Thread.yield(); // await index advance
-                    else if (QA.compareAndSet(a, k, t, null)) {
-                        BASE.setOpaque(this, b);
-                        return t;
+            for (;;) {
+                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (d = b - s) < 0 &&
+                    (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (b++ == base) {
+                        if (t != null) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                return t;
+                            }
+                        }
+                        else if (d == -1)
+                            break; // now empty
                     }
                 }
+                else
+                    break;
             }
             return null;
         }
@@ -944,59 +986,96 @@
          * Takes next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> nextLocalTask() {
-            ForkJoinTask<?> t = null;
-            int md = id, b, s, d, cap; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (cap = a.length) > 0 &&
-                (d = (s = top) - (b = base)) > 0) {
-                if ((md & FIFO) == 0 || d == 1) {
-                    if ((t = (ForkJoinTask<?>)
-                         QA.getAndSet(a, (cap - 1) & --s, null)) != null)
-                        TOP.setOpaque(this, s);
-                }
-                else if ((t = (ForkJoinTask<?>)
-                          QA.getAndSet(a, (cap - 1) & b++, null)) != null) {
-                    BASE.setOpaque(this, b);
-                }
-                else // on contention in FIFO mode, use regular poll
-                    t = poll();
-            }
-            return t;
+            return (config < 0) ? poll() : pop();
         }
 
         /**
          * Returns next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> peek() {
-            int cap; ForkJoinTask<?>[] a;
-            return ((a = array) != null && (cap = a.length) > 0) ?
-                a[(cap - 1) & ((id & FIFO) != 0 ? base : top - 1)] : null;
+            int al; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (al = a.length) > 0) ?
+                a[(al - 1) & (config < 0 ? base : top - 1)] : null;
         }
 
         /**
          * Pops the given task only if it is at the current top.
          */
         final boolean tryUnpush(ForkJoinTask<?> task) {
-            boolean popped = false;
-            int s, cap; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (cap = a.length) > 0 &&
-                (s = top) != base &&
-                (popped = QA.compareAndSet(a, (cap - 1) & --s, task, null)))
-                TOP.setOpaque(this, s);
-            return popped;
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                if (U.compareAndSwapObject(a, offset, task, null)) {
+                    top = s;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Shared version of push. Fails if already locked.
+         *
+         * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
+         */
+        final int sharedPush(ForkJoinTask<?> task) {
+            int stat;
+            if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                int b = base, s = top, al, d; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0 &&
+                    al - 1 + (d = b - s) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;                 // relaxed writes OK here
+                    qlock = 0;
+                    stat = (d < 0 && b == base) ? d : 0;
+                }
+                else {
+                    growAndSharedPush(task);
+                    stat = 0;
+                }
+            }
+            else
+                stat = 1;
+            return stat;
+        }
+
+        /**
+         * Helper for sharedPush; called only when locked and resize
+         * needed.
+         */
+        private void growAndSharedPush(ForkJoinTask<?> task) {
+            try {
+                growArray();
+                int s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;
+                }
+            } finally {
+                qlock = 0;
+            }
         }
 
         /**
          * Shared version of tryUnpush.
          */
-        final boolean tryLockedUnpush(ForkJoinTask<?> task) {
+        final boolean trySharedUnpush(ForkJoinTask<?> task) {
             boolean popped = false;
-            int s = top - 1, k, cap; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (cap = a.length) > 0 &&
-                a[k = (cap - 1) & s] == task && tryLockPhase()) {
-                if (top == s + 1 && array == a &&
-                    (popped = QA.compareAndSet(a, k, task, null)))
-                    top = s;
-                releasePhaseLock();
+            int s = top - 1, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
+                if (t == task &&
+                    U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                    if (top == s + 1 && array == a &&
+                        U.compareAndSwapObject(a, offset, task, null)) {
+                        popped = true;
+                        top = s;
+                    }
+                    U.putOrderedInt(this, QLOCK, 0);
+                }
             }
             return popped;
         }
@@ -1005,150 +1084,252 @@
          * Removes and cancels all known tasks, ignoring any exceptions.
          */
         final void cancelAll() {
-            for (ForkJoinTask<?> t; (t = poll()) != null; )
+            ForkJoinTask<?> t;
+            if ((t = currentJoin) != null) {
+                currentJoin = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            if ((t = currentSteal) != null) {
+                currentSteal = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            while ((t = poll()) != null)
                 ForkJoinTask.cancelIgnoringExceptions(t);
         }
 
         // Specialized execution methods
 
         /**
-         * Runs the given (stolen) task if nonnull, as well as
-         * remaining local tasks and others available from the given
-         * queue, up to bound n (to avoid infinite unfairness).
+         * Pops and executes up to POLL_LIMIT tasks or until empty.
          */
-        final void topLevelExec(ForkJoinTask<?> t, WorkQueue q, int n) {
-            if (t != null && q != null) { // hoist checks
-                int nstolen = 1;
-                for (;;) {
-                    t.doExec();
-                    if (n-- < 0)
-                        break;
-                    else if ((t = nextLocalTask()) == null) {
-                        if ((t = q.poll()) == null)
+        final void localPopAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & --s;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        top = s;
+                        (currentSteal = t).doExec();
+                        if (++nexec > POLL_LIMIT)
                             break;
-                        else
-                            ++nstolen;
+                    }
+                    else
+                        break;
+                }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Polls and executes up to POLL_LIMIT tasks or until empty.
+         */
+        final void localPollAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & b++;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        base = b;
+                        t.doExec();
+                        if (++nexec > POLL_LIMIT)
+                            break;
                     }
                 }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Executes the given task and (some) remaining local tasks.
+         */
+        final void runTask(ForkJoinTask<?> task) {
+            if (task != null) {
+                task.doExec();
+                if (config < 0)
+                    localPollAndExec();
+                else
+                    localPopAndExec();
+                int ns = ++nsteals;
                 ForkJoinWorkerThread thread = owner;
-                nsteals += nstolen;
-                source = 0;
+                currentSteal = null;
+                if (ns < 0)           // collect on overflow
+                    transferStealCount(pool);
                 if (thread != null)
                     thread.afterTopLevelExec();
             }
         }
 
         /**
-         * If present, removes task from queue and executes it.
+         * Adds steal count to pool steal count if it exists, and resets.
          */
-        final void tryRemoveAndExec(ForkJoinTask<?> task) {
-            ForkJoinTask<?>[] a; int s, cap;
-            if ((a = array) != null && (cap = a.length) > 0 &&
-                (s = top) - base > 0) { // traverse from top
-                for (int m = cap - 1, ns = s - 1, i = ns; ; --i) {
-                    int index = i & m;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)QA.get(a, index);
-                    if (t == null)
-                        break;
-                    else if (t == task) {
-                        if (QA.compareAndSet(a, index, t, null)) {
-                            top = ns;   // safely shift down
-                            for (int j = i; j != ns; ++j) {
-                                ForkJoinTask<?> f;
-                                int pindex = (j + 1) & m;
-                                f = (ForkJoinTask<?>)QA.get(a, pindex);
-                                QA.setVolatile(a, pindex, null);
-                                int jindex = j & m;
-                                QA.setRelease(a, jindex, f);
-                            }
-                            VarHandle.releaseFence();
-                            t.doExec();
-                        }
-                        break;
-                    }
+        final void transferStealCount(ForkJoinPool p) {
+            AuxState aux;
+            if (p != null && (aux = p.auxState) != null) {
+                long s = nsteals;
+                nsteals = 0;            // if negative, correct for overflow
+                if (s < 0) s = Integer.MAX_VALUE;
+                aux.lock();
+                try {
+                    aux.stealCount += s;
+                } finally {
+                    aux.unlock();
                 }
             }
         }
 
         /**
-         * Tries to pop and run tasks within the target's computation
-         * until done, not found, or limit exceeded.
+         * If present, removes from queue and executes the given task,
+         * or any other cancelled task. Used only by awaitJoin.
          *
-         * @param task root of CountedCompleter computation
-         * @param limit max runs, or zero for no limit
-         * @param shared true if must lock to extract task
-         * @return task status on exit
+         * @return true if queue empty and task not known to be done
          */
-        final int helpCC(CountedCompleter<?> task, int limit, boolean shared) {
-            int status = 0;
-            if (task != null && (status = task.status) >= 0) {
-                int s, k, cap; ForkJoinTask<?>[] a;
-                while ((a = array) != null && (cap = a.length) > 0 &&
-                       (s = top) - base > 0) {
-                    CountedCompleter<?> v = null;
-                    ForkJoinTask<?> o = a[k = (cap - 1) & (s - 1)];
-                    if (o instanceof CountedCompleter) {
-                        CountedCompleter<?> t = (CountedCompleter<?>)o;
-                        for (CountedCompleter<?> f = t;;) {
-                            if (f != task) {
-                                if ((f = f.completer) == null)
-                                    break;
-                            }
-                            else if (shared) {
-                                if (tryLockPhase()) {
-                                    if (top == s && array == a &&
-                                        QA.compareAndSet(a, k, t, null)) {
-                                        top = s - 1;
-                                        v = t;
-                                    }
-                                    releasePhaseLock();
+        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
+            if (task != null && task.status >= 0) {
+                int b, s, d, al; ForkJoinTask<?>[] a;
+                while ((d = (b = base) - (s = top)) < 0 &&
+                       (a = array) != null && (al = a.length) > 0) {
+                    for (;;) {      // traverse from s to b
+                        int index = --s & (al - 1);
+                        long offset = (index << ASHIFT) + ABASE;
+                        ForkJoinTask<?> t = (ForkJoinTask<?>)
+                            U.getObjectVolatile(a, offset);
+                        if (t == null)
+                            break;                   // restart
+                        else if (t == task) {
+                            boolean removed = false;
+                            if (s + 1 == top) {      // pop
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    top = s;
+                                    removed = true;
                                 }
-                                break;
                             }
-                            else {
-                                if (QA.compareAndSet(a, k, t, null)) {
-                                    top = s - 1;
-                                    v = t;
-                                }
-                                break;
+                            else if (base == b)      // replace with proxy
+                                removed = U.compareAndSwapObject(a, offset, t,
+                                                                 new EmptyTask());
+                            if (removed) {
+                                ForkJoinTask<?> ps = currentSteal;
+                                (currentSteal = task).doExec();
+                                currentSteal = ps;
                             }
-                        }
-                    }
-                    if (v != null)
-                        v.doExec();
-                    if ((status = task.status) < 0 || v == null ||
-                        (limit != 0 && --limit == 0))
-                        break;
-                }
-            }
-            return status;
-        }
-
-        /**
-         * Tries to poll and run AsynchronousCompletionTasks until
-         * none found or blocker is released
-         *
-         * @param blocker the blocker
-         */
-        final void helpAsyncBlocker(ManagedBlocker blocker) {
-            if (blocker != null) {
-                int b, k, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
-                while ((a = array) != null && (cap = a.length) > 0 &&
-                       top - (b = base) > 0) {
-                    t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
-                    if (blocker.isReleasable())
-                        break;
-                    else if (base == b++ && t != null) {
-                        if (!(t instanceof CompletableFuture.
-                              AsynchronousCompletionTask))
                             break;
-                        else if (QA.compareAndSet(a, k, t, null)) {
-                            BASE.setOpaque(this, b);
-                            t.doExec();
+                        }
+                        else if (t.status < 0 && s + 1 == top) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                top = s;
+                            }
+                            break;                  // was cancelled
+                        }
+                        else if (++d == 0) {
+                            if (base != b)          // rescan
+                                break;
+                            return false;
+                        }
+                    }
+                    if (task.status < 0)
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Pops task if in the same CC computation as the given task,
+         * in either shared or owned mode. Used only by helpComplete.
+         */
+        final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & (s - 1);
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o instanceof CountedCompleter) {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if ((mode & IS_OWNED) == 0) {
+                                boolean popped = false;
+                                if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                                    if (top == s && array == a &&
+                                        U.compareAndSwapObject(a, offset,
+                                                               t, null)) {
+                                        popped = true;
+                                        top = s - 1;
+                                    }
+                                    U.putOrderedInt(this, QLOCK, 0);
+                                    if (popped)
+                                        return t;
+                                }
+                            }
+                            else if (U.compareAndSwapObject(a, offset,
+                                                            t, null)) {
+                                top = s - 1;
+                                return t;
+                            }
+                            break;
+                        }
+                        else if ((r = r.completer) == null) // try parent
+                            break;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Steals and runs a task in the same CC computation as the
+         * given task if one exists and can be taken without
+         * contention. Otherwise returns a checksum/control value for
+         * use by method helpComplete.
+         *
+         * @return 1 if successful, 2 if retryable (lost to another
+         * stealer), -1 if non-empty but no matching task found, else
+         * the base index, forced negative.
+         */
+        final int pollAndExecCC(CountedCompleter<?> task) {
+            ForkJoinTask<?>[] a;
+            int b = base, s = top, al, h;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o == null)
+                    h = 2;                      // retryable
+                else if (!(o instanceof CountedCompleter))
+                    h = -1;                     // unmatchable
+                else {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if (b++ == base &&
+                                U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                t.doExec();
+                                h = 1;          // success
+                            }
+                            else
+                                h = 2;          // lost CAS
+                            break;
+                        }
+                        else if ((r = r.completer) == null) {
+                            h = -1;             // unmatched
+                            break;
                         }
                     }
                 }
             }
+            else
+                h = b | Integer.MIN_VALUE;      // to sense movement on re-poll
+            return h;
         }
 
         /**
@@ -1156,24 +1337,29 @@
          */
         final boolean isApparentlyUnblocked() {
             Thread wt; Thread.State s;
-            return ((wt = owner) != null &&
+            return (scanState >= 0 &&
+                    (wt = owner) != null &&
                     (s = wt.getState()) != Thread.State.BLOCKED &&
                     s != Thread.State.WAITING &&
                     s != Thread.State.TIMED_WAITING);
         }
 
-        // VarHandle mechanics.
-        static final VarHandle PHASE;
-        static final VarHandle BASE;
-        static final VarHandle TOP;
+        // Unsafe mechanics. Note that some are (and must be) the same as in FJP
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long QLOCK;
+        private static final int ABASE;
+        private static final int ASHIFT;
         static {
             try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
-                BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
-                TOP = l.findVarHandle(WorkQueue.class, "top", int.class);
+                QLOCK = U.objectFieldOffset
+                    (WorkQueue.class.getDeclaredField("qlock"));
+                ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+                int scale = U.arrayIndexScale(ForkJoinTask[].class);
+                if ((scale & (scale - 1)) != 0)
+                    throw new Error("array index scale not a power of two");
+                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
             } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
+                throw new Error(e);
             }
         }
     }
@@ -1189,7 +1375,7 @@
 
     /**
      * Permission required for callers of methods that may start or
-     * kill threads.
+     * kill threads.  Also used as a static lock in tryInitialize.
      */
     static final RuntimePermission modifyThreadPermission;
 
@@ -1230,15 +1416,18 @@
     // static configuration constants
 
     /**
-     * Default idle timeout value (in milliseconds) for the thread
-     * triggering quiescence to park waiting for new work
+     * Initial timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work. On timeout,
+     * the thread will instead try to shrink the number of workers.
+     * The value should be large enough to avoid overly aggressive
+     * shrinkage during most transient stalls (long GCs etc).
      */
-    private static final long DEFAULT_KEEPALIVE = 60_000L;
+    private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
 
     /**
-     * Undershoot tolerance for idle timeouts
+     * Tolerance for idle timeouts, to cope with timer undershoots.
      */
-    private static final long TIMEOUT_SLOP = 20L;
+    private static final long TIMEOUT_SLOP_MS =   20L; // 20ms
 
     /**
      * The default value for COMMON_MAX_SPARES.  Overridable using the
@@ -1258,7 +1447,7 @@
 
     /*
      * Bits and masks for field ctl, packed with 4 16 bit subfields:
-     * RC: Number of released (unqueued) workers minus target parallelism
+     * AC: Number of active running workers minus target parallelism
      * TC: Number of total workers minus target parallelism
      * SS: version count and status of top waiting thread
      * ID: poolIndex of top of Treiber stack of waiters
@@ -1267,30 +1456,26 @@
      * (including version bits) as sp=(int)ctl.  The offsets of counts
      * by the target parallelism and the positionings of fields makes
      * it possible to perform the most common checks via sign tests of
-     * fields: When ac is negative, there are not enough unqueued
+     * fields: When ac is negative, there are not enough active
      * workers, when tc is negative, there are not enough total
      * workers.  When sp is non-zero, there are waiting workers.  To
      * deal with possibly negative fields, we use casts in and out of
      * "short" and/or signed shifts to maintain signedness.
      *
-     * Because it occupies uppermost bits, we can add one release count
-     * using getAndAddLong of RC_UNIT, rather than CAS, when returning
+     * Because it occupies uppermost bits, we can add one active count
+     * using getAndAddLong of AC_UNIT, rather than CAS, when returning
      * from a blocked join.  Other updates entail multiple subfields
      * and masking, requiring CAS.
-     *
-     * The limits packed in field "bounds" are also offset by the
-     * parallelism level to make them comparable to the ctl rc and tc
-     * fields.
      */
 
     // Lower and upper word masks
     private static final long SP_MASK    = 0xffffffffL;
     private static final long UC_MASK    = ~SP_MASK;
 
-    // Release counts
-    private static final int  RC_SHIFT   = 48;
-    private static final long RC_UNIT    = 0x0001L << RC_SHIFT;
-    private static final long RC_MASK    = 0xffffL << RC_SHIFT;
+    // Active counts
+    private static final int  AC_SHIFT   = 48;
+    private static final long AC_UNIT    = 0x0001L << AC_SHIFT;
+    private static final long AC_MASK    = 0xffffL << AC_SHIFT;
 
     // Total counts
     private static final int  TC_SHIFT   = 32;
@@ -1298,22 +1483,52 @@
     private static final long TC_MASK    = 0xffffL << TC_SHIFT;
     private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
 
-    // Instance fields
+    // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
+    private static final int  STARTED    = 1;
+    private static final int  STOP       = 1 << 1;
+    private static final int  TERMINATED = 1 << 2;
+    private static final int  SHUTDOWN   = 1 << 31;
 
-    volatile long stealCount;            // collects worker nsteals
-    final long keepAlive;                // milliseconds before dropping if idle
-    int indexSeed;                       // next worker index
-    final int bounds;                    // min, max threads packed as shorts
-    volatile int mode;                   // parallelism, runstate, queue mode
-    WorkQueue[] workQueues;              // main registry
-    final String workerNamePrefix;       // for worker thread string; sync lock
+    // Instance fields
+    volatile long ctl;                   // main pool control
+    volatile int runState;
+    final int config;                    // parallelism, mode
+    AuxState auxState;                   // lock, steal counts
+    volatile WorkQueue[] workQueues;     // main registry
+    final String workerNamePrefix;       // to create worker name string
     final ForkJoinWorkerThreadFactory factory;
     final UncaughtExceptionHandler ueh;  // per-worker UEH
-    final Predicate<? super ForkJoinPool> saturate;
 
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    // @jdk.internal.vm.annotation.Contended("fjpctl") // segregate
-    volatile long ctl;                   // main pool control
+    /**
+     * Instantiates fields upon first submission, or upon shutdown if
+     * no submissions. If checkTermination true, also responds to
+     * termination by external calls submitting tasks.
+     */
+    private void tryInitialize(boolean checkTermination) {
+        if (runState == 0) { // bootstrap by locking static field
+            int p = config & SMASK;
+            int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
+            n |= n >>> 1;    // create workQueues array with size a power of two
+            n |= n >>> 2;
+            n |= n >>> 4;
+            n |= n >>> 8;
+            n |= n >>> 16;
+            n = ((n + 1) << 1) & SMASK;
+            AuxState aux = new AuxState();
+            WorkQueue[] ws = new WorkQueue[n];
+            synchronized (modifyThreadPermission) { // double-check
+                if (runState == 0) {
+                    workQueues = ws;
+                    auxState = aux;
+                    runState = STARTED;
+                }
+            }
+        }
+        if (checkTermination && runState < 0) {
+            tryTerminate(false, false); // help terminate
+            throw new RejectedExecutionException();
+        }
+    }
 
     // Creating, registering and deregistering workers
 
@@ -1322,14 +1537,18 @@
      * count has already been incremented as a reservation.  Invokes
      * deregisterWorker on any failure.
      *
+     * @param isSpare true if this is a spare thread
      * @return true if successful
      */
-    private boolean createWorker() {
+    private boolean createWorker(boolean isSpare) {
         ForkJoinWorkerThreadFactory fac = factory;
         Throwable ex = null;
         ForkJoinWorkerThread wt = null;
+        WorkQueue q;
         try {
             if (fac != null && (wt = fac.newThread(this)) != null) {
+                if (isSpare && (q = wt.workQueue) != null)
+                    q.config |= SPARE_WORKER;
                 wt.start();
                 return true;
             }
@@ -1350,10 +1569,10 @@
      */
     private void tryAddWorker(long c) {
         do {
-            long nc = ((RC_MASK & (c + RC_UNIT)) |
+            long nc = ((AC_MASK & (c + AC_UNIT)) |
                        (TC_MASK & (c + TC_UNIT)));
-            if (ctl == c && CTL.compareAndSet(this, c, nc)) {
-                createWorker();
+            if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
+                createWorker(false);
                 break;
             }
         } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
@@ -1368,55 +1587,41 @@
      */
     final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
         UncaughtExceptionHandler handler;
-        wt.setDaemon(true);                             // configure thread
+        AuxState aux;
+        wt.setDaemon(true);                           // configure thread
         if ((handler = ueh) != null)
             wt.setUncaughtExceptionHandler(handler);
-        int tid = 0;                                    // for thread name
-        int idbits = mode & FIFO;
-        String prefix = workerNamePrefix;
         WorkQueue w = new WorkQueue(this, wt);
-        if (prefix != null) {
-            synchronized (prefix) {
-                WorkQueue[] ws = workQueues; int n;
-                int s = indexSeed += SEED_INCREMENT;
-                idbits |= (s & ~(SMASK | FIFO | DORMANT));
-                if (ws != null && (n = ws.length) > 1) {
-                    int m = n - 1;
-                    tid = m & ((s << 1) | 1);           // odd-numbered indices
-                    for (int probes = n >>> 1;;) {      // find empty slot
-                        WorkQueue q;
-                        if ((q = ws[tid]) == null || q.phase == QUIET)
-                            break;
-                        else if (--probes == 0) {
-                            tid = n | 1;                // resize below
-                            break;
+        int i = 0;                                    // assign a pool index
+        int mode = config & MODE_MASK;
+        if ((aux = auxState) != null) {
+            aux.lock();
+            try {
+                int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
+                WorkQueue[] ws = workQueues;
+                if (ws != null && (n = ws.length) > 0) {
+                    i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
+                    if (ws[i] != null) {              // collision
+                        int probes = 0;               // step by approx half n
+                        int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
+                        while (ws[i = (i + step) & m] != null) {
+                            if (++probes >= n) {
+                                workQueues = ws = Arrays.copyOf(ws, n <<= 1);
+                                m = n - 1;
+                                probes = 0;
+                            }
                         }
-                        else
-                            tid = (tid + 2) & m;
                     }
-                    w.phase = w.id = tid | idbits;      // now publishable
-
-                    if (tid < n)
-                        ws[tid] = w;
-                    else {                              // expand array
-                        int an = n << 1;
-                        WorkQueue[] as = new WorkQueue[an];
-                        as[tid] = w;
-                        int am = an - 1;
-                        for (int j = 0; j < n; ++j) {
-                            WorkQueue v;                // copy external queue
-                            if ((v = ws[j]) != null)    // position may change
-                                as[v.id & am & SQMASK] = v;
-                            if (++j >= n)
-                                break;
-                            as[j] = ws[j];              // copy worker
-                        }
-                        workQueues = as;
-                    }
+                    w.hint = s;                       // use as random seed
+                    w.config = i | mode;
+                    w.scanState = i | (s & 0x7fff0000); // random seq bits
+                    ws[i] = w;
                 }
+            } finally {
+                aux.unlock();
             }
-            wt.setName(prefix.concat(Integer.toString(tid)));
         }
+        wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
         return w;
     }
 
@@ -1431,48 +1636,64 @@
      */
     final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
         WorkQueue w = null;
-        int phase = 0;
         if (wt != null && (w = wt.workQueue) != null) {
-            Object lock = workerNamePrefix;
-            int wid = w.id;
-            long ns = (long)w.nsteals & 0xffffffffL;
-            if (lock != null) {
-                synchronized (lock) {
-                    WorkQueue[] ws; int n, i;         // remove index from array
-                    if ((ws = workQueues) != null && (n = ws.length) > 0 &&
-                        ws[i = wid & (n - 1)] == w)
-                        ws[i] = null;
-                    stealCount += ns;
+            AuxState aux; WorkQueue[] ws;          // remove index from array
+            int idx = w.config & SMASK;
+            int ns = w.nsteals;
+            if ((aux = auxState) != null) {
+                aux.lock();
+                try {
+                    if ((ws = workQueues) != null && ws.length > idx &&
+                        ws[idx] == w)
+                        ws[idx] = null;
+                    aux.stealCount += ns;
+                } finally {
+                    aux.unlock();
                 }
             }
-            phase = w.phase;
         }
-        if (phase != QUIET) {                         // else pre-adjusted
+        if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
             long c;                                   // decrement counts
-            do {} while (!CTL.weakCompareAndSet
-                         (this, c = ctl, ((RC_MASK & (c - RC_UNIT)) |
-                                          (TC_MASK & (c - TC_UNIT)) |
-                                          (SP_MASK & c))));
+            do {} while (!U.compareAndSwapLong
+                         (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
+                                               (TC_MASK & (c - TC_UNIT)) |
+                                               (SP_MASK & c))));
         }
-        if (w != null)
+        if (w != null) {
+            w.currentSteal = null;
+            w.qlock = -1;                             // ensure set
             w.cancelAll();                            // cancel remaining tasks
-
-        if (!tryTerminate(false, false) &&            // possibly replace worker
-            w != null && w.array != null)             // avoid repeated failures
-            signalWork();
-
+        }
+        while (tryTerminate(false, false) >= 0) {     // possibly replace
+            WorkQueue[] ws; int wl, sp; long c;
+            if (w == null || w.array == null ||
+                (ws = workQueues) == null || (wl = ws.length) <= 0)
+                break;
+            else if ((sp = (int)(c = ctl)) != 0) {    // wake up replacement
+                if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
+                    break;
+            }
+            else if (ex != null && (c & ADD_WORKER) != 0L) {
+                tryAddWorker(c);                      // create replacement
+                break;
+            }
+            else                                      // don't need replacement
+                break;
+        }
         if (ex == null)                               // help clean on way out
             ForkJoinTask.helpExpungeStaleExceptions();
         else                                          // rethrow
             ForkJoinTask.rethrow(ex);
     }
 
+    // Signalling
+
     /**
-     * Tries to create or release a worker if too few are running.
+     * Tries to create or activate a worker if too few are active.
      */
     final void signalWork() {
         for (;;) {
-            long c; int sp; WorkQueue[] ws; int i; WorkQueue v;
+            long c; int sp, i; WorkQueue v; WorkQueue[] ws;
             if ((c = ctl) >= 0L)                      // enough workers
                 break;
             else if ((sp = (int)c) == 0) {            // no idle workers
@@ -1487,14 +1708,12 @@
             else if ((v = ws[i]) == null)
                 break;                                // terminating
             else {
-                int np = sp & ~UNSIGNALLED;
-                int vp = v.phase;
-                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + RC_UNIT));
-                Thread vt = v.owner;
-                if (sp == vp && CTL.compareAndSet(this, c, nc)) {
-                    v.phase = np;
-                    if (vt != null && v.source < 0)
-                        LockSupport.unpark(vt);
+                int ns = sp & ~UNSIGNALLED;
+                int vs = v.scanState;
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+                if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                    v.scanState = ns;
+                    LockSupport.unpark(v.parker);
                     break;
                 }
             }
@@ -1502,181 +1721,502 @@
     }
 
     /**
-     * Tries to decrement counts (sometimes implicitly) and possibly
-     * arrange for a compensating worker in preparation for blocking:
-     * If not all core workers yet exist, creates one, else if any are
-     * unreleased (possibly including caller) releases one, else if
-     * fewer than the minimum allowed number of workers running,
-     * checks to see that they are all active, and if so creates an
-     * extra worker unless over maximum limit and policy is to
-     * saturate.  Most of these steps can fail due to interference, in
-     * which case 0 is returned so caller will retry. A negative
-     * return value indicates that the caller doesn't need to
-     * re-adjust counts when later unblocked.
+     * Signals and releases worker v if it is top of idle worker
+     * stack.  This performs a one-shot version of signalWork only if
+     * there is (apparently) at least one idle worker.
      *
-     * @return 1: block then adjust, -1: block without adjust, 0 : retry
+     * @param c incoming ctl value
+     * @param v if non-null, a worker
+     * @param inc the increment to active count (zero when compensating)
+     * @return true if successful
      */
-    private int tryCompensate(WorkQueue w) {
-        int t, n, sp;
-        long c = ctl;
-        WorkQueue[] ws = workQueues;
-        if ((t = (short)(c >>> TC_SHIFT)) >= 0) {
-            if (ws == null || (n = ws.length) <= 0 || w == null)
-                return 0;                        // disabled
-            else if ((sp = (int)c) != 0) {       // replace or release
-                WorkQueue v = ws[sp & (n - 1)];
-                int wp = w.phase;
-                long uc = UC_MASK & ((wp < 0) ? c + RC_UNIT : c);
-                int np = sp & ~UNSIGNALLED;
-                if (v != null) {
-                    int vp = v.phase;
-                    Thread vt = v.owner;
-                    long nc = ((long)v.stackPred & SP_MASK) | uc;
-                    if (vp == sp && CTL.compareAndSet(this, c, nc)) {
-                        v.phase = np;
-                        if (vt != null && v.source < 0)
-                            LockSupport.unpark(vt);
-                        return (wp < 0) ? -1 : 1;
-                    }
-                }
-                return 0;
-            }
-            else if ((int)(c >> RC_SHIFT) -      // reduce parallelism
-                     (short)(bounds & SMASK) > 0) {
-                long nc = ((RC_MASK & (c - RC_UNIT)) | (~RC_MASK & c));
-                return CTL.compareAndSet(this, c, nc) ? 1 : 0;
-            }
-            else {                               // validate
-                int md = mode, pc = md & SMASK, tc = pc + t, bc = 0;
-                boolean unstable = false;
-                for (int i = 1; i < n; i += 2) {
-                    WorkQueue q; Thread wt; Thread.State ts;
-                    if ((q = ws[i]) != null) {
-                        if (q.source == 0) {
-                            unstable = true;
-                            break;
-                        }
-                        else {
-                            --tc;
-                            if ((wt = q.owner) != null &&
-                                ((ts = wt.getState()) == Thread.State.BLOCKED ||
-                                 ts == Thread.State.WAITING))
-                                ++bc;            // worker is blocking
-                        }
-                    }
-                }
-                if (unstable || tc != 0 || ctl != c)
-                    return 0;                    // inconsistent
-                else if (t + pc >= MAX_CAP || t >= (bounds >>> SWIDTH)) {
-                    Predicate<? super ForkJoinPool> sat;
-                    if ((sat = saturate) != null && sat.test(this))
-                        return -1;
-                    else if (bc < pc) {          // lagging
-                        Thread.yield();          // for retry spins
-                        return 0;
-                    }
-                    else
-                        throw new RejectedExecutionException(
-                            "Thread limit exceeded replacing blocked worker");
-                }
-            }
-        }
-
-        long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); // expand pool
-        return CTL.compareAndSet(this, c, nc) && createWorker() ? 1 : 0;
-    }
-
-    /**
-     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
-     * See above for explanation.
-     */
-    final void runWorker(WorkQueue w) {
-        int r = (w.id ^ ThreadLocalRandom.nextSecondarySeed()) | FIFO; // rng
-        w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; // initialize
-        for (;;) {
-            int phase;
-            if (scan(w, r)) {                     // scan until apparently empty
-                r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // move (xorshift)
-            }
-            else if ((phase = w.phase) >= 0) {    // enqueue, then rescan
-                long np = (w.phase = (phase + SS_SEQ) | UNSIGNALLED) & SP_MASK;
-                long c, nc;
-                do {
-                    w.stackPred = (int)(c = ctl);
-                    nc = ((c - RC_UNIT) & UC_MASK) | np;
-                } while (!CTL.weakCompareAndSet(this, c, nc));
-            }
-            else {                                // already queued
-                int pred = w.stackPred;
-                Thread.interrupted();             // clear before park
-                w.source = DORMANT;               // enable signal
-                long c = ctl;
-                int md = mode, rc = (md & SMASK) + (int)(c >> RC_SHIFT);
-                if (md < 0)                       // terminating
-                    break;
-                else if (rc <= 0 && (md & SHUTDOWN) != 0 &&
-                         tryTerminate(false, false))
-                    break;                        // quiescent shutdown
-                else if (rc <= 0 && pred != 0 && phase == (int)c) {
-                    long nc = (UC_MASK & (c - TC_UNIT)) | (SP_MASK & pred);
-                    long d = keepAlive + System.currentTimeMillis();
-                    LockSupport.parkUntil(this, d);
-                    if (ctl == c &&               // drop on timeout if all idle
-                        d - System.currentTimeMillis() <= TIMEOUT_SLOP &&
-                        CTL.compareAndSet(this, c, nc)) {
-                        w.phase = QUIET;
-                        break;
-                    }
-                }
-                else if (w.phase < 0)
-                    LockSupport.park(this);       // OK if spuriously woken
-                w.source = 0;                     // disable signal
-            }
-        }
-    }
-
-    /**
-     * Scans for and if found executes one or more top-level tasks from a queue.
-     *
-     * @return true if found an apparently non-empty queue, and
-     * possibly ran task(s).
-     */
-    private boolean scan(WorkQueue w, int r) {
-        WorkQueue[] ws; int n;
-        if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
-            for (int m = n - 1, j = r & m;;) {
-                WorkQueue q; int b;
-                if ((q = ws[j]) != null && q.top != (b = q.base)) {
-                    int qid = q.id;
-                    ForkJoinTask<?>[] a; int cap, k; ForkJoinTask<?> t;
-                    if ((a = q.array) != null && (cap = a.length) > 0) {
-                        t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
-                        if (q.base == b++ && t != null &&
-                            QA.compareAndSet(a, k, t, null)) {
-                            q.base = b;
-                            w.source = qid;
-                            if (q.top - b > 0)
-                                signalWork();
-                            w.topLevelExec(t, q,  // random fairness bound
-                                           r & ((n << TOP_BOUND_SHIFT) - 1));
-                        }
-                    }
-                    return true;
-                }
-                else if (--n > 0)
-                    j = (j + 1) & m;
-                else
-                    break;
+    private boolean tryRelease(long c, WorkQueue v, long inc) {
+        int sp = (int)c, ns = sp & ~UNSIGNALLED;
+        if (v != null) {
+            int vs = v.scanState;
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
+            if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+                return true;
             }
         }
         return false;
     }
 
     /**
+     * With approx probability of a missed signal, tries (once) to
+     * reactivate worker w (or some other worker), failing if stale or
+     * known to be already active.
+     *
+     * @param w the worker
+     * @param ws the workQueue array to use
+     * @param r random seed
+     */
+    private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
+        long c; int sp, wl; WorkQueue v;
+        if ((sp = (int)(c = ctl)) != 0 && w != null &&
+            ws != null && (wl = ws.length) > 0 &&
+            ((sp ^ r) & SS_SEQ) == 0 &&
+            (v = ws[(wl - 1) & sp]) != null) {
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+            int ns = sp & ~UNSIGNALLED;
+            if (w.scanState < 0 &&
+                v.scanState == sp &&
+                U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+            }
+        }
+    }
+
+    /**
+     * If worker w exists and is active, enqueues and sets status to inactive.
+     *
+     * @param w the worker
+     * @param ss current (non-negative) scanState
+     */
+    private void inactivate(WorkQueue w, int ss) {
+        int ns = (ss + SS_SEQ) | UNSIGNALLED;
+        long lc = ns & SP_MASK, nc, c;
+        if (w != null) {
+            w.scanState = ns;
+            do {
+                nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
+                w.stackPred = (int)c;
+            } while (!U.compareAndSwapLong(this, CTL, c, nc));
+        }
+    }
+
+    /**
+     * Possibly blocks worker w waiting for signal, or returns
+     * negative status if the worker should terminate. May return
+     * without status change if multiple stale unparks and/or
+     * interrupts occur.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int awaitWork(WorkQueue w) {
+        int stat = 0;
+        if (w != null && w.scanState < 0) {
+            long c = ctl;
+            if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
+                stat = timedAwaitWork(w, c);     // possibly quiescent
+            else if ((runState & STOP) != 0)
+                stat = w.qlock = -1;             // pool terminating
+            else if (w.scanState < 0) {
+                w.parker = Thread.currentThread();
+                if (w.scanState < 0)             // recheck after write
+                    LockSupport.park(this);
+                w.parker = null;
+                if ((runState & STOP) != 0)
+                    stat = w.qlock = -1;         // recheck
+                else if (w.scanState < 0)
+                    Thread.interrupted();        // clear status
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * Possibly triggers shutdown and tries (once) to block worker
+     * when pool is (or may be) quiescent. Waits up to a duration
+     * determined by number of workers.  On timeout, if ctl has not
+     * changed, terminates the worker, which will in turn wake up
+     * another worker to possibly repeat this process.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int timedAwaitWork(WorkQueue w, long c) {
+        int stat = 0;
+        int scale = 1 - (short)(c >>> TC_SHIFT);
+        long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
+                         System.currentTimeMillis());
+        if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
+            w != null && w.scanState < 0) {
+            int ss; AuxState aux;
+            w.parker = Thread.currentThread();
+            if (w.scanState < 0)
+                LockSupport.parkUntil(this, deadline);
+            w.parker = null;
+            if ((runState & STOP) != 0)
+                stat = w.qlock = -1;         // pool terminating
+            else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
+                     (int)c == ss && (aux = auxState) != null && ctl == c &&
+                     deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
+                aux.lock();
+                try {                        // pre-deregister
+                    WorkQueue[] ws;
+                    int cfg = w.config, idx = cfg & SMASK;
+                    long nc = ((UC_MASK & (c - TC_UNIT)) |
+                               (SP_MASK & w.stackPred));
+                    if ((runState & STOP) == 0 &&
+                        (ws = workQueues) != null &&
+                        idx < ws.length && idx >= 0 && ws[idx] == w &&
+                        U.compareAndSwapLong(this, CTL, c, nc)) {
+                        ws[idx] = null;
+                        w.config = cfg | UNREGISTERED;
+                        stat = w.qlock = -1;
+                    }
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * If the given worker is a spare with no queued tasks, and there
+     * are enough existing workers, drops it from ctl counts and sets
+     * its state to terminated.
+     *
+     * @param w the calling worker -- must be a spare
+     * @return true if dropped (in which case it must not process more tasks)
+     */
+    private boolean tryDropSpare(WorkQueue w) {
+        if (w != null && w.isEmpty()) {           // no local tasks
+            long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
+            while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
+                   ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
+                   (ws = workQueues) != null && (wl = ws.length) > 0) {
+                boolean dropped, canDrop;
+                if (sp == 0) {                    // no queued workers
+                    long nc = ((AC_MASK & (c - AC_UNIT)) |
+                               (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
+                    dropped = U.compareAndSwapLong(this, CTL, c, nc);
+                }
+                else if (
+                    (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
+                    dropped = false;              // stale; retry
+                else {
+                    long nc = v.stackPred & SP_MASK;
+                    if (w == v || w.scanState >= 0) {
+                        canDrop = true;           // w unqueued or topmost
+                        nc |= ((AC_MASK & c) |    // ensure replacement
+                               (TC_MASK & (c - TC_UNIT)));
+                    }
+                    else {                        // w may be queued
+                        canDrop = false;          // help uncover
+                        nc |= ((AC_MASK & (c + AC_UNIT)) |
+                               (TC_MASK & c));
+                    }
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        v.scanState = sp & ~UNSIGNALLED;
+                        LockSupport.unpark(v.parker);
+                        dropped = canDrop;
+                    }
+                    else
+                        dropped = false;
+                }
+                if (dropped) {                    // pre-deregister
+                    int cfg = w.config, idx = cfg & SMASK;
+                    if (idx >= 0 && idx < ws.length && ws[idx] == w)
+                        ws[idx] = null;
+                    w.config = cfg | UNREGISTERED;
+                    w.qlock = -1;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     */
+    final void runWorker(WorkQueue w) {
+        w.growArray();                                  // allocate queue
+        int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
+        long seed = w.hint * 0xdaba0b6eb09322e3L;       // initial random seed
+        if ((runState & STOP) == 0) {
+            for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
+                if (bound == 0 && tryDropSpare(w))
+                    break;
+                // high bits of prev seed for step; current low bits for idx
+                int step = (int)(r >>> 48) | 1;
+                r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
+                if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
+                    break;
+            }
+        }
+    }
+
+    // Scanning for tasks
+
+    /**
+     * Repeatedly scans for and tries to steal and execute (via
+     * workQueue.runTask) a queued task. Each scan traverses queues in
+     * pseudorandom permutation. Upon finding a non-empty queue, makes
+     * at most the given bound attempts to re-poll (fewer if
+     * contended) on the same queue before returning (impossible
+     * scanState value) 0 to restart scan. Else returns after at least
+     * 1 and at most 32 full scans.
+     *
+     * @param w the worker (via its WorkQueue)
+     * @param bound repoll bound as bitmask (0 if spare)
+     * @param step (circular) index increment per iteration (must be odd)
+     * @param r a random seed for origin index
+     * @return negative if should await signal
+     */
+    private int scan(WorkQueue w, int bound, int step, int r) {
+        int stat = 0, wl; WorkQueue[] ws;
+        if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1,
+                     origin = m & r, idx = origin,
+                     npolls = 0,
+                     ss = w.scanState;;) {         // negative if inactive
+                WorkQueue q; ForkJoinTask<?>[] a; int b, al;
+                if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
+                    (a = q.array) != null && (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (t == null)
+                        break;                     // empty or busy
+                    else if (b++ != q.base)
+                        break;                     // busy
+                    else if (ss < 0) {
+                        tryReactivate(w, ws, r);
+                        break;                     // retry upon rescan
+                    }
+                    else if (!U.compareAndSwapObject(a, offset, t, null))
+                        break;                     // contended
+                    else {
+                        q.base = b;
+                        w.currentSteal = t;
+                        if (b != q.top)            // propagate signal
+                            signalWork();
+                        w.runTask(t);
+                        if (++npolls > bound)
+                            break;
+                    }
+                }
+                else if (npolls != 0)              // rescan
+                    break;
+                else if ((idx = (idx + step) & m) == origin) {
+                    if (ss < 0) {                  // await signal
+                        stat = ss;
+                        break;
+                    }
+                    else if (r >= 0) {
+                        inactivate(w, ss);
+                        break;
+                    }
+                    else
+                        r <<= 1;                   // at most 31 rescans
+                }
+            }
+        }
+        return stat;
+    }
+
+    // Joining tasks
+
+    /**
+     * Tries to steal and run tasks within the target's computation.
+     * Uses a variant of the top-level algorithm, restricted to tasks
+     * with the given task as ancestor: It prefers taking and running
+     * eligible tasks popped from the worker's own queue (via
+     * popCC). Otherwise it scans others, randomly moving on
+     * contention or execution, deciding to give up based on a
+     * checksum (via return codes from pollAndExecCC). The maxTasks
+     * argument supports external usages; internal calls use zero,
+     * allowing unbounded steps (external calls trap non-positive
+     * values).
+     *
+     * @param w caller
+     * @param maxTasks if non-zero, the maximum number of other tasks to run
+     * @return task status on exit
+     */
+    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+                           int maxTasks) {
+        WorkQueue[] ws; int s = 0, wl;
+        if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
+            task != null && w != null) {
+            for (int m = wl - 1,
+                     mode = w.config,
+                     r = ~mode,                  // scanning seed
+                     origin = r & m, k = origin, // first queue to scan
+                     step = 3,                   // first scan step
+                     h = 1,                      // 1:ran, >1:contended, <0:hash
+                     oldSum = 0, checkSum = 0;;) {
+                CountedCompleter<?> p; WorkQueue q; int i;
+                if ((s = task.status) < 0)
+                    break;
+                if (h == 1 && (p = w.popCC(task, mode)) != null) {
+                    p.doExec();                  // run local task
+                    if (maxTasks != 0 && --maxTasks == 0)
+                        break;
+                    origin = k;                  // reset
+                    oldSum = checkSum = 0;
+                }
+                else {                           // poll other worker queues
+                    if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
+                        h = 0;
+                    else if ((h = q.pollAndExecCC(task)) < 0)
+                        checkSum += h;
+                    if (h > 0) {
+                        if (h == 1 && maxTasks != 0 && --maxTasks == 0)
+                            break;
+                        step = (r >>> 16) | 3;
+                        r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+                        k = origin = r & m;      // move and restart
+                        oldSum = checkSum = 0;
+                    }
+                    else if ((k = (k + step) & m) == origin) {
+                        if (oldSum == (oldSum = checkSum))
+                            break;
+                        checkSum = 0;
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Tries to locate and execute tasks for a stealer of the given
+     * task, or in turn one of its stealers. Traces currentSteal ->
+     * currentJoin links looking for a thread working on a descendant
+     * of the given task and with a non-empty queue to steal back and
+     * execute tasks from. The first call to this method upon a
+     * waiting join will often entail scanning/search, (which is OK
+     * because the joiner has nothing better to do), but this method
+     * leaves hints in workers to speed up subsequent calls.
+     *
+     * @param w caller
+     * @param task the task to join
+     */
+    private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
+        if (task != null && w != null) {
+            ForkJoinTask<?> ps = w.currentSteal;
+            WorkQueue[] ws; int wl, oldSum = 0;
+            outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
+                          (ws = workQueues) != null && (wl = ws.length) > 0) {
+                ForkJoinTask<?> subtask;
+                int m = wl - 1, checkSum = 0;          // for stability check
+                WorkQueue j = w, v;                    // v is subtask stealer
+                descent: for (subtask = task; subtask.status >= 0; ) {
+                    for (int h = j.hint | 1, k = 0, i;;) {
+                        if ((v = ws[i = (h + (k << 1)) & m]) != null) {
+                            if (v.currentSteal == subtask) {
+                                j.hint = i;
+                                break;
+                            }
+                            checkSum += v.base;
+                        }
+                        if (++k > m)                   // can't find stealer
+                            break outer;
+                    }
+
+                    for (;;) {                         // help v or descend
+                        ForkJoinTask<?>[] a; int b, al;
+                        if (subtask.status < 0)        // too late to help
+                            break descent;
+                        checkSum += (b = v.base);
+                        ForkJoinTask<?> next = v.currentJoin;
+                        ForkJoinTask<?> t = null;
+                        if ((a = v.array) != null && (al = a.length) > 0) {
+                            int index = (al - 1) & b;
+                            long offset = ((long)index << ASHIFT) + ABASE;
+                            t = (ForkJoinTask<?>)
+                                U.getObjectVolatile(a, offset);
+                            if (t != null && b++ == v.base) {
+                                if (j.currentJoin != subtask ||
+                                    v.currentSteal != subtask ||
+                                    subtask.status < 0)
+                                    break descent;     // stale
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    v.base = b;
+                                    w.currentSteal = t;
+                                    for (int top = w.top;;) {
+                                        t.doExec();    // help
+                                        w.currentSteal = ps;
+                                        if (task.status < 0)
+                                            break outer;
+                                        if (w.top == top)
+                                            break;     // run local tasks
+                                        if ((t = w.pop()) == null)
+                                            break descent;
+                                        w.currentSteal = t;
+                                    }
+                                }
+                            }
+                        }
+                        if (t == null && b == v.base && b - v.top >= 0) {
+                            if ((subtask = next) == null) {  // try to descend
+                                if (next == v.currentJoin &&
+                                    oldSum == (oldSum = checkSum))
+                                    break outer;
+                                break descent;
+                            }
+                            j = v;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Tries to decrement active count (sometimes implicitly) and
+     * possibly release or create a compensating worker in preparation
+     * for blocking. Returns false (retryable by caller), on
+     * contention, detected staleness, instability, or termination.
+     *
+     * @param w caller
+     */
+    private boolean tryCompensate(WorkQueue w) {
+        boolean canBlock; int wl;
+        long c = ctl;
+        WorkQueue[] ws = workQueues;
+        int pc = config & SMASK;
+        int ac = pc + (int)(c >> AC_SHIFT);
+        int tc = pc + (short)(c >> TC_SHIFT);
+        if (w == null || w.qlock < 0 || pc == 0 ||  // terminating or disabled
+            ws == null || (wl = ws.length) <= 0)
+            canBlock = false;
+        else {
+            int m = wl - 1, sp;
+            boolean busy = true;                    // validate ac
+            for (int i = 0; i <= m; ++i) {
+                int k; WorkQueue v;
+                if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
+                    v.scanState >= 0 && v.currentSteal == null) {
+                    busy = false;
+                    break;
+                }
+            }
+            if (!busy || ctl != c)
+                canBlock = false;                   // unstable or stale
+            else if ((sp = (int)c) != 0)            // release idle worker
+                canBlock = tryRelease(c, ws[m & sp], 0L);
+            else if (tc >= pc && ac > 1 && w.isEmpty()) {
+                long nc = ((AC_MASK & (c - AC_UNIT)) |
+                           (~AC_MASK & c));         // uncompensated
+                canBlock = U.compareAndSwapLong(this, CTL, c, nc);
+            }
+            else if (tc >= MAX_CAP ||
+                     (this == common && tc >= pc + COMMON_MAX_SPARES))
+                throw new RejectedExecutionException(
+                    "Thread limit exceeded replacing blocked worker");
+            else {                                  // similar to tryAddWorker
+                boolean isSpare = (tc >= pc);
+                long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
+                canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
+                            createWorker(isSpare)); // throws on exception
+            }
+        }
+        return canBlock;
+    }
+
+    /**
      * Helps and/or blocks until the given task is done or timeout.
-     * First tries locally helping, then scans other queues for a task
-     * produced by one of w's stealers; compensating and blocking if
-     * none are found (rescanning if tryCompensate fails).
      *
      * @param w caller
      * @param task the task
@@ -1685,165 +2225,62 @@
      */
     final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
         int s = 0;
-        int seed = ThreadLocalRandom.nextSecondarySeed();
-        if (w != null && task != null &&
-            (!(task instanceof CountedCompleter) ||
-             (s = w.helpCC((CountedCompleter<?>)task, 0, false)) >= 0)) {
-            w.tryRemoveAndExec(task);
-            int src = w.source, id = w.id;
-            int r = (seed >>> 16) | 1, step = (seed & ~1) | 2;
-            s = task.status;
-            while (s >= 0) {
-                WorkQueue[] ws;
-                int n = (ws = workQueues) == null ? 0 : ws.length, m = n - 1;
-                while (n > 0) {
-                    WorkQueue q; int b;
-                    if ((q = ws[r & m]) != null && q.source == id &&
-                        q.top != (b = q.base)) {
-                        ForkJoinTask<?>[] a; int cap, k;
-                        int qid = q.id;
-                        if ((a = q.array) != null && (cap = a.length) > 0) {
-                            ForkJoinTask<?> t = (ForkJoinTask<?>)
-                                QA.getAcquire(a, k = (cap - 1) & b);
-                            if (q.source == id && q.base == b++ &&
-                                t != null && QA.compareAndSet(a, k, t, null)) {
-                                q.base = b;
-                                w.source = qid;
-                                t.doExec();
-                                w.source = src;
-                            }
-                        }
+        if (w != null) {
+            ForkJoinTask<?> prevJoin = w.currentJoin;
+            if (task != null && (s = task.status) >= 0) {
+                w.currentJoin = task;
+                CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
+                    (CountedCompleter<?>)task : null;
+                for (;;) {
+                    if (cc != null)
+                        helpComplete(w, cc, 0);
+                    else
+                        helpStealer(w, task);
+                    if ((s = task.status) < 0)
                         break;
-                    }
-                    else {
-                        r += step;
-                        --n;
-                    }
-                }
-                if ((s = task.status) < 0)
-                    break;
-                else if (n == 0) { // empty scan
-                    long ms, ns; int block;
+                    long ms, ns;
                     if (deadline == 0L)
-                        ms = 0L;                       // untimed
+                        ms = 0L;
                     else if ((ns = deadline - System.nanoTime()) <= 0L)
-                        break;                         // timeout
+                        break;
                     else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
-                        ms = 1L;                       // avoid 0 for timed wait
-                    if ((block = tryCompensate(w)) != 0) {
+                        ms = 1L;
+                    if (tryCompensate(w)) {
                         task.internalWait(ms);
-                        CTL.getAndAdd(this, (block > 0) ? RC_UNIT : 0L);
+                        U.getAndAddLong(this, CTL, AC_UNIT);
                     }
-                    s = task.status;
+                    if ((s = task.status) < 0)
+                        break;
                 }
+                w.currentJoin = prevJoin;
             }
         }
         return s;
     }
 
-    /**
-     * Runs tasks until {@code isQuiescent()}. Rather than blocking
-     * when tasks cannot be found, rescans until all others cannot
-     * find tasks either.
-     */
-    final void helpQuiescePool(WorkQueue w) {
-        int prevSrc = w.source;
-        int seed = ThreadLocalRandom.nextSecondarySeed();
-        int r = seed >>> 16, step = r | 1;
-        for (int source = prevSrc, released = -1;;) { // -1 until known
-            ForkJoinTask<?> localTask; WorkQueue[] ws;
-            while ((localTask = w.nextLocalTask()) != null)
-                localTask.doExec();
-            if (w.phase >= 0 && released == -1)
-                released = 1;
-            boolean quiet = true, empty = true;
-            int n = (ws = workQueues) == null ? 0 : ws.length;
-            for (int m = n - 1; n > 0; r += step, --n) {
-                WorkQueue q; int b;
-                if ((q = ws[r & m]) != null) {
-                    int qs = q.source;
-                    if (q.top != (b = q.base)) {
-                        quiet = empty = false;
-                        ForkJoinTask<?>[] a; int cap, k;
-                        int qid = q.id;
-                        if ((a = q.array) != null && (cap = a.length) > 0) {
-                            if (released == 0) {    // increment
-                                released = 1;
-                                CTL.getAndAdd(this, RC_UNIT);
-                            }
-                            ForkJoinTask<?> t = (ForkJoinTask<?>)
-                                QA.getAcquire(a, k = (cap - 1) & b);
-                            if (q.base == b++ && t != null &&
-                                QA.compareAndSet(a, k, t, null)) {
-                                q.base = b;
-                                w.source = qid;
-                                t.doExec();
-                                w.source = source = prevSrc;
-                            }
-                        }
-                        break;
-                    }
-                    else if ((qs & QUIET) == 0)
-                        quiet = false;
-                }
-            }
-            if (quiet) {
-                if (released == 0)
-                    CTL.getAndAdd(this, RC_UNIT);
-                w.source = prevSrc;
-                break;
-            }
-            else if (empty) {
-                if (source != QUIET)
-                    w.source = source = QUIET;
-                if (released == 1) {                 // decrement
-                    released = 0;
-                    CTL.getAndAdd(this, RC_MASK & -RC_UNIT);
-                }
-            }
-        }
-    }
+    // Specialized scanning
 
     /**
-     * Scans for and returns a polled task, if available.
-     * Used only for untracked polls.
-     *
-     * @param submissionsOnly if true, only scan submission queues
+     * Returns a (probably) non-empty steal queue, if one is found
+     * during a scan, else null.  This method must be retried by
+     * caller if, by the time it tries to use the queue, it is empty.
      */
-    private ForkJoinTask<?> pollScan(boolean submissionsOnly) {
-        WorkQueue[] ws; int n;
-        rescan: while ((mode & STOP) == 0 && (ws = workQueues) != null &&
-                      (n = ws.length) > 0) {
-            int m = n - 1;
-            int r = ThreadLocalRandom.nextSecondarySeed();
-            int h = r >>> 16;
-            int origin, step;
-            if (submissionsOnly) {
-                origin = (r & ~1) & m;         // even indices and steps
-                step = (h & ~1) | 2;
-            }
-            else {
-                origin = r & m;
-                step = h | 1;
-            }
-            boolean nonempty = false;
-            for (int i = origin, oldSum = 0, checkSum = 0;;) {
-                WorkQueue q;
-                if ((q = ws[i]) != null) {
-                    int b; ForkJoinTask<?> t;
-                    if (q.top - (b = q.base) > 0) {
-                        nonempty = true;
-                        if ((t = q.poll()) != null)
-                            return t;
-                    }
-                    else
-                        checkSum += b + q.id;
+    private WorkQueue findNonEmptyStealQueue() {
+        WorkQueue[] ws; int wl;  // one-shot version of scan loop
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            int m = wl - 1, origin = r & m;
+            for (int k = origin, oldSum = 0, checkSum = 0;;) {
+                WorkQueue q; int b;
+                if ((q = ws[k]) != null) {
+                    if ((b = q.base) - q.top < 0)
+                        return q;
+                    checkSum += b;
                 }
-                if ((i = (i + step) & m) == origin) {
-                    if (!nonempty && oldSum == (oldSum = checkSum))
-                        break rescan;
+                if ((k = (k + 1) & m) == origin) {
+                    if (oldSum == (oldSum = checkSum))
+                        break;
                     checkSum = 0;
-                    nonempty = false;
                 }
             }
         }
@@ -1851,132 +2288,61 @@
     }
 
     /**
+     * Runs tasks until {@code isQuiescent()}. We piggyback on
+     * active count ctl maintenance, but rather than blocking
+     * when tasks cannot be found, we rescan until all others cannot
+     * find tasks either.
+     */
+    final void helpQuiescePool(WorkQueue w) {
+        ForkJoinTask<?> ps = w.currentSteal; // save context
+        int wc = w.config;
+        for (boolean active = true;;) {
+            long c; WorkQueue q; ForkJoinTask<?> t;
+            if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
+                (w.currentSteal = t).doExec();
+                w.currentSteal = ps;
+            }
+            else if ((q = findNonEmptyStealQueue()) != null) {
+                if (!active) {      // re-establish active count
+                    active = true;
+                    U.getAndAddLong(this, CTL, AC_UNIT);
+                }
+                if ((t = q.pollAt(q.base)) != null) {
+                    (w.currentSteal = t).doExec();
+                    w.currentSteal = ps;
+                    if (++w.nsteals < 0)
+                        w.transferStealCount(this);
+                }
+            }
+            else if (active) {      // decrement active count without queuing
+                long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
+                if (U.compareAndSwapLong(this, CTL, c, nc))
+                    active = false;
+            }
+            else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
+                     U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
+                break;
+        }
+    }
+
+    /**
      * Gets and removes a local or stolen task for the given worker.
      *
      * @return a task, if available
      */
     final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
-        ForkJoinTask<?> t;
-        if (w == null || (t = w.nextLocalTask()) == null)
-            t = pollScan(false);
-        return t;
-    }
-
-    // External operations
-
-    /**
-     * Adds the given task to a submission queue at submitter's
-     * current queue, creating one if null or contended.
-     *
-     * @param task the task. Caller must ensure non-null.
-     */
-    final void externalPush(ForkJoinTask<?> task) {
-        int r;                                // initialize caller's probe
-        if ((r = ThreadLocalRandom.getProbe()) == 0) {
-            ThreadLocalRandom.localInit();
-            r = ThreadLocalRandom.getProbe();
-        }
-        for (;;) {
+        for (ForkJoinTask<?> t;;) {
             WorkQueue q;
-            int md = mode, n;
-            WorkQueue[] ws = workQueues;
-            if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
-                throw new RejectedExecutionException();
-            else if ((q = ws[(n - 1) & r & SQMASK]) == null) { // add queue
-                int qid = (r | QUIET) & ~(FIFO | OWNED);
-                Object lock = workerNamePrefix;
-                ForkJoinTask<?>[] qa =
-                    new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
-                q = new WorkQueue(this, null);
-                q.array = qa;
-                q.id = qid;
-                q.source = QUIET;
-                if (lock != null) {     // unless disabled, lock pool to install
-                    synchronized (lock) {
-                        WorkQueue[] vs; int i, vn;
-                        if ((vs = workQueues) != null && (vn = vs.length) > 0 &&
-                            vs[i = qid & (vn - 1) & SQMASK] == null)
-                            vs[i] = q;  // else another thread already installed
-                    }
-                }
-            }
-            else if (!q.tryLockPhase()) // move if busy
-                r = ThreadLocalRandom.advanceProbe(r);
-            else {
-                if (q.lockedPush(task))
-                    signalWork();
-                return;
-            }
+            if ((t = w.nextLocalTask()) != null)
+                return t;
+            if ((q = findNonEmptyStealQueue()) == null)
+                return null;
+            if ((t = q.pollAt(q.base)) != null)
+                return t;
         }
     }
 
     /**
-     * Pushes a possibly-external submission.
-     */
-    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
-        Thread t; ForkJoinWorkerThread w; WorkQueue q;
-        if (task == null)
-            throw new NullPointerException();
-        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
-            (w = (ForkJoinWorkerThread)t).pool == this &&
-            (q = w.workQueue) != null)
-            q.push(task);
-        else
-            externalPush(task);
-        return task;
-    }
-
-    /**
-     * Returns common pool queue for an external thread.
-     */
-    static WorkQueue commonSubmitterQueue() {
-        ForkJoinPool p = common;
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; int n;
-        return (p != null && (ws = p.workQueues) != null &&
-                (n = ws.length) > 0) ?
-            ws[(n - 1) & r & SQMASK] : null;
-    }
-
-    /**
-     * Performs tryUnpush for an external submitter.
-     */
-    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; WorkQueue w; int n;
-        return ((ws = workQueues) != null &&
-                (n = ws.length) > 0 &&
-                (w = ws[(n - 1) & r & SQMASK]) != null &&
-                w.tryLockedUnpush(task));
-    }
-
-    /**
-     * Performs helpComplete for an external submitter.
-     */
-    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; WorkQueue w; int n;
-        return ((ws = workQueues) != null && (n = ws.length) > 0 &&
-                (w = ws[(n - 1) & r & SQMASK]) != null) ?
-            w.helpCC(task, maxTasks, true) : 0;
-    }
-
-    /**
-     * Tries to steal and run tasks within the target's computation.
-     * The maxTasks argument supports external usages; internal calls
-     * use zero, allowing unbounded steps (external calls trap
-     * non-positive values).
-     *
-     * @param w caller
-     * @param maxTasks if non-zero, the maximum number of other tasks to run
-     * @return task status on exit
-     */
-    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
-                           int maxTasks) {
-        return (w == null) ? 0 : w.helpCC(task, maxTasks, false);
-    }
-
-    /**
      * Returns a cheap heuristic guide for task partitioning when
      * programmers, frameworks, tools, or languages have little or no
      * idea about task granularity.  In essence, by offering this
@@ -2020,12 +2386,10 @@
      */
     static int getSurplusQueuedTaskCount() {
         Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
-        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
-            (pool = (wt = (ForkJoinWorkerThread)t).pool) != null &&
-            (q = wt.workQueue) != null) {
-            int p = pool.mode & SMASK;
-            int a = p + (int)(pool.ctl >> RC_SHIFT);
-            int n = q.top - q.base;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
+            int n = (q = wt.workQueue).top - q.base;
+            int a = (int)(pool.ctl >> AC_SHIFT) + p;
             return n - (a > (p >>>= 1) ? 0 :
                         a > (p >>>= 1) ? 1 :
                         a > (p >>>= 1) ? 2 :
@@ -2035,7 +2399,7 @@
         return 0;
     }
 
-    // Termination
+    //  Termination
 
     /**
      * Possibly initiates and/or completes termination.
@@ -2043,89 +2407,198 @@
      * @param now if true, unconditionally terminate, else only
      * if no work and no active workers
      * @param enable if true, terminate when next possible
-     * @return true if terminating or terminated
+     * @return -1: terminating/terminated, 0: retry if internal caller, else 1
      */
-    private boolean tryTerminate(boolean now, boolean enable) {
-        int md; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+    private int tryTerminate(boolean now, boolean enable) {
+        int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
 
-        while (((md = mode) & SHUTDOWN) == 0) {
+        while ((rs = runState) >= 0) {
             if (!enable || this == common)        // cannot shutdown
-                return false;
+                return 1;
+            else if (rs == 0)
+                tryInitialize(false);             // ensure initialized
             else
-                MODE.compareAndSet(this, md, md | SHUTDOWN);
+                U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
         }
 
-        while (((md = mode) & STOP) == 0) {       // try to initiate termination
-            if (!now) {                           // check if quiescent & empty
+        if ((rs & STOP) == 0) {                   // try to initiate termination
+            if (!now) {                           // check quiescence
                 for (long oldSum = 0L;;) {        // repeat until stable
-                    boolean running = false;
+                    WorkQueue[] ws; WorkQueue w; int b;
                     long checkSum = ctl;
-                    WorkQueue[] ws = workQueues;
-                    if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
-                        running = true;
-                    else if (ws != null) {
-                        WorkQueue w;
+                    if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
+                        return 0;                 // still active workers
+                    if ((ws = workQueues) != null) {
                         for (int i = 0; i < ws.length; ++i) {
                             if ((w = ws[i]) != null) {
-                                int s = w.source, p = w.phase;
-                                int d = w.id, b = w.base;
-                                if (b != w.top ||
-                                    ((d & 1) == 1 && (s >= 0 || p >= 0))) {
-                                    running = true;
-                                    break;     // working, scanning, or have work
-                                }
-                                checkSum += (((long)s << 48) + ((long)p << 32) +
-                                             ((long)b << 16) + (long)d);
+                                checkSum += (b = w.base);
+                                if (w.currentSteal != null || b != w.top)
+                                    return 0;     // retry if internal caller
                             }
                         }
                     }
-                    if (((md = mode) & STOP) != 0)
-                        break;                 // already triggered
-                    else if (running)
-                        return false;
-                    else if (workQueues == ws && oldSum == (oldSum = checkSum))
+                    if (oldSum == (oldSum = checkSum))
                         break;
                 }
             }
-            if ((md & STOP) == 0)
-                MODE.compareAndSet(this, md, md | STOP);
+            do {} while (!U.compareAndSwapInt(this, RUNSTATE,
+                                              rs = runState, rs | STOP));
         }
 
-        while (((md = mode) & TERMINATED) == 0) { // help terminate others
-            for (long oldSum = 0L;;) {            // repeat until stable
-                WorkQueue[] ws; WorkQueue w;
-                long checkSum = ctl;
-                if ((ws = workQueues) != null) {
-                    for (int i = 0; i < ws.length; ++i) {
-                        if ((w = ws[i]) != null) {
-                            ForkJoinWorkerThread wt = w.owner;
-                            w.cancelAll();        // clear queues
-                            if (wt != null) {
+        for (long oldSum = 0L;;) {                // repeat until stable
+            WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
+            long checkSum = ctl;
+            if ((ws = workQueues) != null) {      // help terminate others
+                for (int i = 0; i < ws.length; ++i) {
+                    if ((w = ws[i]) != null) {
+                        w.cancelAll();            // clear queues
+                        checkSum += w.base;
+                        if (w.qlock >= 0) {
+                            w.qlock = -1;         // racy set OK
+                            if ((wt = w.owner) != null) {
                                 try {             // unblock join or park
                                     wt.interrupt();
                                 } catch (Throwable ignore) {
                                 }
                             }
-                            checkSum += ((long)w.phase << 32) + w.base;
                         }
                     }
                 }
-                if (((md = mode) & TERMINATED) != 0 ||
-                    (workQueues == ws && oldSum == (oldSum = checkSum)))
-                    break;
             }
-            if ((md & TERMINATED) != 0)
+            if (oldSum == (oldSum = checkSum))
                 break;
-            else if ((md & SMASK) + (short)(ctl >>> TC_SHIFT) > 0)
-                break;
-            else if (MODE.compareAndSet(this, md, md | TERMINATED)) {
-                synchronized (this) {
-                    notifyAll();                  // for awaitTermination
-                }
-                break;
+        }
+
+        if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
+            runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
+            synchronized (this) {
+                notifyAll();                      // for awaitTermination
             }
         }
-        return true;
+
+        return -1;
+    }
+
+    // External operations
+
+    /**
+     * Constructs and tries to install a new external queue,
+     * failing if the workQueues array already has a queue at
+     * the given index.
+     *
+     * @param index the index of the new queue
+     */
+    private void tryCreateExternalQueue(int index) {
+        AuxState aux;
+        if ((aux = auxState) != null && index >= 0) {
+            WorkQueue q = new WorkQueue(this, null);
+            q.config = index;
+            q.scanState = ~UNSIGNALLED;
+            q.qlock = 1;                   // lock queue
+            boolean installed = false;
+            aux.lock();
+            try {                          // lock pool to install
+                WorkQueue[] ws;
+                if ((ws = workQueues) != null && index < ws.length &&
+                    ws[index] == null) {
+                    ws[index] = q;         // else throw away
+                    installed = true;
+                }
+            } finally {
+                aux.unlock();
+            }
+            if (installed) {
+                try {
+                    q.growArray();
+                } finally {
+                    q.qlock = 0;
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds the given task to a submission queue at submitter's
+     * current queue. Also performs secondary initialization upon the
+     * first submission of the first task to the pool, and detects
+     * first submission by an external thread and creates a new shared
+     * queue if the one at index if empty or contended.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        int r;                            // initialize caller's probe
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();
+            r = ThreadLocalRandom.getProbe();
+        }
+        for (;;) {
+            WorkQueue q; int wl, k, stat;
+            int rs = runState;
+            WorkQueue[] ws = workQueues;
+            if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
+                tryInitialize(true);
+            else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
+                tryCreateExternalQueue(k);
+            else if ((stat = q.sharedPush(task)) < 0)
+                break;
+            else if (stat == 0) {
+                signalWork();
+                break;
+            }
+            else                          // move if busy
+                r = ThreadLocalRandom.advanceProbe(r);
+        }
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread w; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this &&
+            (q = w.workQueue) != null)
+            q.push(task);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p = common;
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; int wl;
+        return (p != null && (ws = p.workQueues) != null &&
+                (wl = ws.length) > 0) ?
+            ws[(wl - 1) & r & SQMASK] : null;
+    }
+
+    /**
+     * Performs tryUnpush for an external submitter.
+     */
+    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int wl;
+        return ((ws = workQueues) != null &&
+                (wl = ws.length) > 0 &&
+                (w = ws[(wl - 1) & r & SQMASK]) != null &&
+                w.trySharedUnpush(task));
+    }
+
+    /**
+     * Performs helpComplete for an external submitter.
+     */
+    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+        WorkQueue[] ws; int wl;
+        int r = ThreadLocalRandom.getProbe();
+        return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
+            helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
     }
 
     // Exported methods
@@ -2134,10 +2607,9 @@
 
     /**
      * Creates a {@code ForkJoinPool} with parallelism equal to {@link
-     * java.lang.Runtime#availableProcessors}, using defaults for all
-     * other parameters (see {@link #ForkJoinPool(int,
-     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
-     * int, int, int, Predicate, long, TimeUnit)}).
+     * java.lang.Runtime#availableProcessors}, using the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
      *
      * @throws SecurityException if a security manager exists and
      *         the caller is not permitted to modify threads
@@ -2146,16 +2618,14 @@
      */
     public ForkJoinPool() {
         this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
-             defaultForkJoinWorkerThreadFactory, null, false,
-             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+             defaultForkJoinWorkerThreadFactory, null, false);
     }
 
     /**
      * Creates a {@code ForkJoinPool} with the indicated parallelism
-     * level, using defaults for all other parameters (see {@link
-     * #ForkJoinPool(int, ForkJoinWorkerThreadFactory,
-     * UncaughtExceptionHandler, boolean, int, int, int, Predicate,
-     * long, TimeUnit)}).
+     * level, the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
      *
      * @param parallelism the parallelism level
      * @throws IllegalArgumentException if parallelism less than or
@@ -2166,15 +2636,11 @@
      *         java.lang.RuntimePermission}{@code ("modifyThread")}
      */
     public ForkJoinPool(int parallelism) {
-        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false,
-             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
     }
 
     /**
-     * Creates a {@code ForkJoinPool} with the given parameters (using
-     * defaults for others -- see {@link #ForkJoinPool(int,
-     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
-     * int, int, int, Predicate, long, TimeUnit)}).
+     * Creates a {@code ForkJoinPool} with the given parameters.
      *
      * @param parallelism the parallelism level. For default value,
      * use {@link java.lang.Runtime#availableProcessors}.
@@ -2201,186 +2667,43 @@
                         ForkJoinWorkerThreadFactory factory,
                         UncaughtExceptionHandler handler,
                         boolean asyncMode) {
-        this(parallelism, factory, handler, asyncMode,
-             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
-    }
-
-    /**
-     * Creates a {@code ForkJoinPool} with the given parameters.
-     *
-     * @param parallelism the parallelism level. For default value,
-     * use {@link java.lang.Runtime#availableProcessors}.
-     *
-     * @param factory the factory for creating new threads. For
-     * default value, use {@link #defaultForkJoinWorkerThreadFactory}.
-     *
-     * @param handler the handler for internal worker threads that
-     * terminate due to unrecoverable errors encountered while
-     * executing tasks. For default value, use {@code null}.
-     *
-     * @param asyncMode if true, establishes local first-in-first-out
-     * scheduling mode for forked tasks that are never joined. This
-     * mode may be more appropriate than default locally stack-based
-     * mode in applications in which worker threads only process
-     * event-style asynchronous tasks.  For default value, use {@code
-     * false}.
-     *
-     * @param corePoolSize the number of threads to keep in the pool
-     * (unless timed out after an elapsed keep-alive). Normally (and
-     * by default) this is the same value as the parallelism level,
-     * but may be set to a larger value to reduce dynamic overhead if
-     * tasks regularly block. Using a smaller value (for example
-     * {@code 0}) has the same effect as the default.
-     *
-     * @param maximumPoolSize the maximum number of threads allowed.
-     * When the maximum is reached, attempts to replace blocked
-     * threads fail.  (However, because creation and termination of
-     * different threads may overlap, and may be managed by the given
-     * thread factory, this value may be transiently exceeded.)  To
-     * arrange the same value as is used by default for the common
-     * pool, use {@code 256} plus the {@code parallelism} level. (By
-     * default, the common pool allows a maximum of 256 spare
-     * threads.)  Using a value (for example {@code
-     * Integer.MAX_VALUE}) larger than the implementation's total
-     * thread limit has the same effect as using this limit (which is
-     * the default).
-     *
-     * @param minimumRunnable the minimum allowed number of core
-     * threads not blocked by a join or {@link ManagedBlocker}.  To
-     * ensure progress, when too few unblocked threads exist and
-     * unexecuted tasks may exist, new threads are constructed, up to
-     * the given maximumPoolSize.  For the default value, use {@code
-     * 1}, that ensures liveness.  A larger value might improve
-     * throughput in the presence of blocked activities, but might
-     * not, due to increased overhead.  A value of zero may be
-     * acceptable when submitted tasks cannot have dependencies
-     * requiring additional threads.
-     *
-     * @param saturate if non-null, a predicate invoked upon attempts
-     * to create more than the maximum total allowed threads.  By
-     * default, when a thread is about to block on a join or {@link
-     * ManagedBlocker}, but cannot be replaced because the
-     * maximumPoolSize would be exceeded, a {@link
-     * RejectedExecutionException} is thrown.  But if this predicate
-     * returns {@code true}, then no exception is thrown, so the pool
-     * continues to operate with fewer than the target number of
-     * runnable threads, which might not ensure progress.
-     *
-     * @param keepAliveTime the elapsed time since last use before
-     * a thread is terminated (and then later replaced if needed).
-     * For the default value, use {@code 60, TimeUnit.SECONDS}.
-     *
-     * @param unit the time unit for the {@code keepAliveTime} argument
-     *
-     * @throws IllegalArgumentException if parallelism is less than or
-     *         equal to zero, or is greater than implementation limit,
-     *         or if maximumPoolSize is less than parallelism,
-     *         of if the keepAliveTime is less than or equal to zero.
-     * @throws NullPointerException if the factory is null
-     * @throws SecurityException if a security manager exists and
-     *         the caller is not permitted to modify threads
-     *         because it does not hold {@link
-     *         java.lang.RuntimePermission}{@code ("modifyThread")}
-     * @since 9
-     */
-    public ForkJoinPool(int parallelism,
-                        ForkJoinWorkerThreadFactory factory,
-                        UncaughtExceptionHandler handler,
-                        boolean asyncMode,
-                        int corePoolSize,
-                        int maximumPoolSize,
-                        int minimumRunnable,
-                        Predicate<? super ForkJoinPool> saturate,
-                        long keepAliveTime,
-                        TimeUnit unit) {
-        // check, encode, pack parameters
-        if (parallelism <= 0 || parallelism > MAX_CAP ||
-            maximumPoolSize < parallelism || keepAliveTime <= 0L)
-            throw new IllegalArgumentException();
-        if (factory == null)
-            throw new NullPointerException();
-        long ms = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);
-
-        int corep = Math.min(Math.max(corePoolSize, parallelism), MAX_CAP);
-        long c = ((((long)(-corep)       << TC_SHIFT) & TC_MASK) |
-                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
-        int m = parallelism | (asyncMode ? FIFO : 0);
-        int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - parallelism;
-        int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
-        int b = ((minAvail - parallelism) & SMASK) | (maxSpares << SWIDTH);
-        int n = (parallelism > 1) ? parallelism - 1 : 1; // at least 2 slots
-        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
-        n = (n + 1) << 1; // power of two, including space for submission queues
-
-        this.workerNamePrefix = "ForkJoinPool-" + nextPoolId() + "-worker-";
-        this.workQueues = new WorkQueue[n];
-        this.factory = factory;
-        this.ueh = handler;
-        this.saturate = saturate;
-        this.keepAlive = ms;
-        this.bounds = b;
-        this.mode = m;
-        this.ctl = c;
+        this(checkParallelism(parallelism),
+             checkFactory(factory),
+             handler,
+             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
+             "ForkJoinPool-" + nextPoolId() + "-worker-");
         checkPermission();
     }
 
-    private static Object newInstanceFromSystemProperty(String property)
-        throws ReflectiveOperationException {
-        String className = System.getProperty(property);
-        return (className == null)
-            ? null
-            : ClassLoader.getSystemClassLoader().loadClass(className)
-            .getConstructor().newInstance();
+    private static int checkParallelism(int parallelism) {
+        if (parallelism <= 0 || parallelism > MAX_CAP)
+            throw new IllegalArgumentException();
+        return parallelism;
+    }
+
+    private static ForkJoinWorkerThreadFactory checkFactory
+        (ForkJoinWorkerThreadFactory factory) {
+        if (factory == null)
+            throw new NullPointerException();
+        return factory;
     }
 
     /**
-     * Constructor for common pool using parameters possibly
-     * overridden by system properties
+     * Creates a {@code ForkJoinPool} with the given parameters, without
+     * any security checks or parameter validation.  Invoked directly by
+     * makeCommonPool.
      */
-    private ForkJoinPool(byte forCommonPoolOnly) {
-        int parallelism = -1;
-        ForkJoinWorkerThreadFactory fac = null;
-        UncaughtExceptionHandler handler = null;
-        try {  // ignore exceptions in accessing/parsing properties
-            String pp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.parallelism");
-            if (pp != null)
-                parallelism = Integer.parseInt(pp);
-            fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(
-                "java.util.concurrent.ForkJoinPool.common.threadFactory");
-            handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(
-                "java.util.concurrent.ForkJoinPool.common.exceptionHandler");
-        } catch (Exception ignore) {
-        }
-
-        if (fac == null) {
-            if (System.getSecurityManager() == null)
-                fac = defaultForkJoinWorkerThreadFactory;
-            else // use security-managed default
-                fac = new InnocuousForkJoinWorkerThreadFactory();
-        }
-        if (parallelism < 0 && // default 1 less than #cores
-            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
-            parallelism = 1;
-        if (parallelism > MAX_CAP)
-            parallelism = MAX_CAP;
-
-        long c = ((((long)(-parallelism) << TC_SHIFT) & TC_MASK) |
-                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
-        int b = ((1 - parallelism) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
-        int n = (parallelism > 1) ? parallelism - 1 : 1;
-        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
-        n = (n + 1) << 1;
-
-        this.workerNamePrefix = "ForkJoinPool.commonPool-worker-";
-        this.workQueues = new WorkQueue[n];
-        this.factory = fac;
+    private ForkJoinPool(int parallelism,
+                         ForkJoinWorkerThreadFactory factory,
+                         UncaughtExceptionHandler handler,
+                         int mode,
+                         String workerNamePrefix) {
+        this.workerNamePrefix = workerNamePrefix;
+        this.factory = factory;
         this.ueh = handler;
-        this.saturate = null;
-        this.keepAlive = DEFAULT_KEEPALIVE;
-        this.bounds = b;
-        this.mode = parallelism;
-        this.ctl = c;
+        this.config = (parallelism & SMASK) | mode;
+        long np = (long)(-parallelism); // offset ctl counts
+        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
     }
 
     /**
@@ -2494,13 +2817,15 @@
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
      */
-    @SuppressWarnings("unchecked")
     public ForkJoinTask<?> submit(Runnable task) {
         if (task == null)
             throw new NullPointerException();
-        return externalSubmit((task instanceof ForkJoinTask<?>)
-            ? (ForkJoinTask<Void>) task // avoid re-wrap
-            : new ForkJoinTask.AdaptedRunnableAction(task));
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = new ForkJoinTask.AdaptedRunnableAction(task);
+        return externalSubmit(job);
     }
 
     /**
@@ -2554,8 +2879,8 @@
      * @return the targeted parallelism level of this pool
      */
     public int getParallelism() {
-        int par = mode & SMASK;
-        return (par > 0) ? par : 1;
+        int par;
+        return ((par = config & SMASK) > 0) ? par : 1;
     }
 
     /**
@@ -2577,7 +2902,7 @@
      * @return the number of worker threads
      */
     public int getPoolSize() {
-        return ((mode & SMASK) + (short)(ctl >>> TC_SHIFT));
+        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
     }
 
     /**
@@ -2587,7 +2912,7 @@
      * @return {@code true} if this pool uses async mode
      */
     public boolean getAsyncMode() {
-        return (mode & FIFO) != 0;
+        return (config & FIFO_QUEUE) != 0;
     }
 
     /**
@@ -2599,9 +2924,8 @@
      * @return the number of worker threads
      */
     public int getRunningThreadCount() {
-        WorkQueue[] ws; WorkQueue w;
-        VarHandle.acquireFence();
         int rc = 0;
+        WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && w.isApparentlyUnblocked())
@@ -2619,7 +2943,7 @@
      * @return the number of active threads
      */
     public int getActiveThreadCount() {
-        int r = (mode & SMASK) + (int)(ctl >> RC_SHIFT);
+        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
         return (r <= 0) ? 0 : r; // suppress momentarily negative values
     }
 
@@ -2635,30 +2959,7 @@
      * @return {@code true} if all threads are currently idle
      */
     public boolean isQuiescent() {
-        for (;;) {
-            long c = ctl;
-            int md = mode, pc = md & SMASK;
-            int tc = pc + (short)(c >>> TC_SHIFT);
-            int rc = pc + (int)(c >> RC_SHIFT);
-            if ((md & (STOP | TERMINATED)) != 0)
-                return true;
-            else if (rc > 0)
-                return false;
-            else {
-                WorkQueue[] ws; WorkQueue v;
-                if ((ws = workQueues) != null) {
-                    for (int i = 1; i < ws.length; i += 2) {
-                        if ((v = ws[i]) != null) {
-                            if (v.source > 0)
-                                return false;
-                            --tc;
-                        }
-                    }
-                }
-                if (tc == 0 && ctl == c)
-                    return true;
-            }
-        }
+        return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
     }
 
     /**
@@ -2673,12 +2974,13 @@
      * @return the number of steals
      */
     public long getStealCount() {
-        long count = stealCount;
+        AuxState sc = auxState;
+        long count = (sc == null) ? 0L : sc.stealCount;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
-                    count += (long)w.nsteals & 0xffffffffL;
+                    count += w.nsteals;
             }
         }
         return count;
@@ -2695,9 +2997,8 @@
      * @return the number of queued tasks
      */
     public long getQueuedTaskCount() {
+        long count = 0;
         WorkQueue[] ws; WorkQueue w;
-        VarHandle.acquireFence();
-        int count = 0;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -2715,9 +3016,8 @@
      * @return the number of queued submissions
      */
     public int getQueuedSubmissionCount() {
-        WorkQueue[] ws; WorkQueue w;
-        VarHandle.acquireFence();
         int count = 0;
+        WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -2735,7 +3035,6 @@
      */
     public boolean hasQueuedSubmissions() {
         WorkQueue[] ws; WorkQueue w;
-        VarHandle.acquireFence();
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && !w.isEmpty())
@@ -2753,7 +3052,15 @@
      * @return the next submission, or {@code null} if none
      */
     protected ForkJoinTask<?> pollSubmission() {
-        return pollScan(true);
+        WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1, i = 0; i < wl; ++i) {
+                if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
+                    return t;
+            }
+        }
+        return null;
     }
 
     /**
@@ -2774,9 +3081,8 @@
      * @return the number of elements transferred
      */
     protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
-        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
-        VarHandle.acquireFence();
         int count = 0;
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
                 if ((w = ws[i]) != null) {
@@ -2799,10 +3105,10 @@
      */
     public String toString() {
         // Use a single pass through workQueues to collect counts
-        int md = mode; // read volatile fields first
-        long c = ctl;
-        long st = stealCount;
         long qt = 0L, qs = 0L; int rc = 0;
+        AuxState sc = auxState;
+        long st = (sc == null) ? 0L : sc.stealCount;
+        long c = ctl;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
@@ -2812,22 +3118,22 @@
                         qs += size;
                     else {
                         qt += size;
-                        st += (long)w.nsteals & 0xffffffffL;
+                        st += w.nsteals;
                         if (w.isApparentlyUnblocked())
                             ++rc;
                     }
                 }
             }
         }
-
-        int pc = (md & SMASK);
+        int pc = (config & SMASK);
         int tc = pc + (short)(c >>> TC_SHIFT);
-        int ac = pc + (int)(c >> RC_SHIFT);
+        int ac = pc + (int)(c >> AC_SHIFT);
         if (ac < 0) // ignore transient negative
             ac = 0;
-        String level = ((md & TERMINATED) != 0 ? "Terminated" :
-                        (md & STOP)       != 0 ? "Terminating" :
-                        (md & SHUTDOWN)   != 0 ? "Shutting down" :
+        int rs = runState;
+        String level = ((rs & TERMINATED) != 0 ? "Terminated" :
+                        (rs & STOP)       != 0 ? "Terminating" :
+                        (rs & SHUTDOWN)   != 0 ? "Shutting down" :
                         "Running");
         return super.toString() +
             "[" + level +
@@ -2890,7 +3196,7 @@
      * @return {@code true} if all tasks have completed following shut down
      */
     public boolean isTerminated() {
-        return (mode & TERMINATED) != 0;
+        return (runState & TERMINATED) != 0;
     }
 
     /**
@@ -2907,8 +3213,8 @@
      * @return {@code true} if terminating but not yet terminated
      */
     public boolean isTerminating() {
-        int md = mode;
-        return (md & STOP) != 0 && (md & TERMINATED) == 0;
+        int rs = runState;
+        return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
     }
 
     /**
@@ -2917,7 +3223,7 @@
      * @return {@code true} if this pool has been shut down
      */
     public boolean isShutdown() {
-        return (mode & SHUTDOWN) != 0;
+        return (runState & SHUTDOWN) != 0;
     }
 
     /**
@@ -2981,19 +3287,30 @@
             helpQuiescePool(wt.workQueue);
             return true;
         }
-        else {
-            for (long startTime = System.nanoTime();;) {
-                ForkJoinTask<?> t;
-                if ((t = pollScan(false)) != null)
-                    t.doExec();
-                else if (isQuiescent())
-                    return true;
-                else if ((System.nanoTime() - startTime) > nanos)
+        long startTime = System.nanoTime();
+        WorkQueue[] ws;
+        int r = 0, wl;
+        boolean found = true;
+        while (!isQuiescent() && (ws = workQueues) != null &&
+               (wl = ws.length) > 0) {
+            if (!found) {
+                if ((System.nanoTime() - startTime) > nanos)
                     return false;
-                else
-                    Thread.yield(); // cannot block
+                Thread.yield(); // cannot block
+            }
+            found = false;
+            for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
+                ForkJoinTask<?> t; WorkQueue q; int b, k;
+                if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
+                    (b = q.base) - q.top < 0) {
+                    found = true;
+                    if ((t = q.pollAt(b)) != null)
+                        t.doExec();
+                    break;
+                }
             }
         }
+        return true;
     }
 
     /**
@@ -3106,22 +3423,19 @@
      */
     public static void managedBlock(ManagedBlocker blocker)
         throws InterruptedException {
-        if (blocker == null) throw new NullPointerException();
         ForkJoinPool p;
         ForkJoinWorkerThread wt;
-        WorkQueue w;
         Thread t = Thread.currentThread();
         if ((t instanceof ForkJoinWorkerThread) &&
-            (p = (wt = (ForkJoinWorkerThread)t).pool) != null &&
-            (w = wt.workQueue) != null) {
-            int block;
+            (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
+            WorkQueue w = wt.workQueue;
             while (!blocker.isReleasable()) {
-                if ((block = p.tryCompensate(w)) != 0) {
+                if (p.tryCompensate(w)) {
                     try {
                         do {} while (!blocker.isReleasable() &&
                                      !blocker.block());
                     } finally {
-                        CTL.getAndAdd(p, (block > 0) ? RC_UNIT : 0L);
+                        U.getAndAddLong(p, CTL, AC_UNIT);
                     }
                     break;
                 }
@@ -3133,29 +3447,6 @@
         }
     }
 
-    /**
-     * If the given executor is a ForkJoinPool, poll and execute
-     * AsynchronousCompletionTasks from worker's queue until none are
-     * available or blocker is released.
-     */
-    static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
-        if (e instanceof ForkJoinPool) {
-            WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
-            ForkJoinPool p = (ForkJoinPool)e;
-            Thread thread = Thread.currentThread();
-            if (thread instanceof ForkJoinWorkerThread &&
-                (wt = (ForkJoinWorkerThread)thread).pool == p)
-                w = wt.workQueue;
-            else if ((r = ThreadLocalRandom.getProbe()) != 0 &&
-                     (ws = p.workQueues) != null && (n = ws.length) > 0)
-                w = ws[(n - 1) & r & SQMASK];
-            else
-                w = null;
-            if (w != null)
-                w.helpAsyncBlocker(blocker);
-        }
-    }
-
     // AbstractExecutorService overrides.  These rely on undocumented
     // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
     // implement RunnableFuture.
@@ -3168,19 +3459,26 @@
         return new ForkJoinTask.AdaptedCallable<T>(callable);
     }
 
-    // VarHandle mechanics
-    private static final VarHandle CTL;
-    private static final VarHandle MODE;
-    static final VarHandle QA;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long CTL;
+    private static final long RUNSTATE;
+    private static final int ABASE;
+    private static final int ASHIFT;
 
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
-            MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
-            QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
+            CTL = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("ctl"));
+            RUNSTATE = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("runState"));
+            ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+            int scale = U.arrayIndexScale(ForkJoinTask[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
@@ -3200,11 +3498,52 @@
             new DefaultForkJoinWorkerThreadFactory();
         modifyThreadPermission = new RuntimePermission("modifyThread");
 
-        common = AccessController.doPrivileged(new PrivilegedAction<>() {
-            public ForkJoinPool run() {
-                return new ForkJoinPool((byte)0); }});
+        common = java.security.AccessController.doPrivileged
+            (new java.security.PrivilegedAction<ForkJoinPool>() {
+                public ForkJoinPool run() { return makeCommonPool(); }});
 
-        COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
+        // report 1 even if threads disabled
+        COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
+    }
+
+    /**
+     * Creates and returns the common pool, respecting user settings
+     * specified via system properties.
+     */
+    static ForkJoinPool makeCommonPool() {
+        int parallelism = -1;
+        ForkJoinWorkerThreadFactory factory = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            String fp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
+            String hp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+            if (fp != null)
+                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
+                           getSystemClassLoader().loadClass(fp).newInstance());
+            if (hp != null)
+                handler = ((UncaughtExceptionHandler)ClassLoader.
+                           getSystemClassLoader().loadClass(hp).newInstance());
+        } catch (Exception ignore) {
+        }
+        if (factory == null) {
+            if (System.getSecurityManager() == null)
+                factory = defaultForkJoinWorkerThreadFactory;
+            else // use security-managed default
+                factory = new InnocuousForkJoinWorkerThreadFactory();
+        }
+        if (parallelism < 0 && // default 1 less than #cores
+            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+            parallelism = 1;
+        if (parallelism > MAX_CAP)
+            parallelism = MAX_CAP;
+        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
+                                "ForkJoinPool.commonPool-worker-");
     }
 
     /**
@@ -3217,20 +3556,27 @@
          * An ACC to restrict permissions for the factory itself.
          * The constructed workers have no permissions set.
          */
-        private static final AccessControlContext ACC = contextWithPermissions(
-            modifyThreadPermission,
-            new RuntimePermission("enableContextClassLoaderOverride"),
-            new RuntimePermission("modifyThreadGroup"),
-            new RuntimePermission("getClassLoader"),
-            new RuntimePermission("setContextClassLoader"));
+        private static final AccessControlContext innocuousAcc;
+        static {
+            Permissions innocuousPerms = new Permissions();
+            innocuousPerms.add(modifyThreadPermission);
+            innocuousPerms.add(new RuntimePermission(
+                                   "enableContextClassLoaderOverride"));
+            innocuousPerms.add(new RuntimePermission(
+                                   "modifyThreadGroup"));
+            innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
+                    new ProtectionDomain(null, innocuousPerms)
+                });
+        }
 
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return AccessController.doPrivileged(
-                new PrivilegedAction<>() {
+            return java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
                     public ForkJoinWorkerThread run() {
                         return new ForkJoinWorkerThread.
-                            InnocuousForkJoinWorkerThread(pool); }},
-                ACC);
+                            InnocuousForkJoinWorkerThread(pool);
+                    }}, innocuousAcc);
         }
     }
+
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
index fd28e84..efccfa5 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -36,8 +36,6 @@
 package java.util.concurrent;
 
 import java.io.Serializable;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
@@ -98,7 +96,7 @@
  * encountering the exception; minimally only the latter.
  *
  * <p>It is possible to define and use ForkJoinTasks that may block,
- * but doing so requires three further considerations: (1) Completion
+ * but doing do requires three further considerations: (1) Completion
  * of few if any <em>other</em> tasks should be dependent on a task
  * that blocks on external synchronization or I/O. Event-style async
  * tasks that are never joined (for example, those subclassing {@link
@@ -138,11 +136,11 @@
  * {@link #isCompletedNormally} is true if a task completed without
  * cancellation or encountering an exception; {@link #isCancelled} is
  * true if the task was cancelled (in which case {@link #getException}
- * returns a {@link CancellationException}); and
+ * returns a {@link java.util.concurrent.CancellationException}); and
  * {@link #isCompletedAbnormally} is true if a task was either
  * cancelled or encountered an exception, in which case {@link
  * #getException} will return either the encountered exception or
- * {@link CancellationException}.
+ * {@link java.util.concurrent.CancellationException}.
  *
  * <p>The ForkJoinTask class is not usually directly subclassed.
  * Instead, you subclass one of the abstract classes that support a
@@ -223,59 +221,52 @@
      * methods in a way that flows well in javadocs.
      */
 
-    /**
+    /*
      * The status field holds run control status bits packed into a
-     * single int to ensure atomicity.  Status is initially zero, and
-     * takes on nonnegative values until completed, upon which it
-     * holds (sign bit) DONE, possibly with ABNORMAL (cancelled or
-     * exceptional) and THROWN (in which case an exception has been
-     * stored). Tasks with dependent blocked waiting joiners have the
-     * SIGNAL bit set.  Completion of a task with SIGNAL set awakens
-     * any waiters via notifyAll. (Waiters also help signal others
-     * upon completion.)
+     * single int to minimize footprint and to ensure atomicity (via
+     * CAS).  Status is initially zero, and takes on nonnegative
+     * values until completed, upon which status (anded with
+     * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
+     * undergoing blocking waits by other threads have the SIGNAL bit
+     * set.  Completion of a stolen task with SIGNAL set awakens any
+     * waiters via notifyAll. Even though suboptimal for some
+     * purposes, we use basic builtin wait/notify to take advantage of
+     * "monitor inflation" in JVMs that we would otherwise need to
+     * emulate to avoid adding further per-task bookkeeping overhead.
+     * We want these monitors to be "fat", i.e., not use biasing or
+     * thin-lock techniques, so use some odd coding idioms that tend
+     * to avoid them, mainly by arranging that every synchronized
+     * block performs a wait, notifyAll or both.
      *
      * These control bits occupy only (some of) the upper half (16
      * bits) of status field. The lower bits are used for user-defined
      * tags.
      */
+
+    /** The run status of this task */
     volatile int status; // accessed directly by pool and workers
-
-    private static final int DONE     = 1 << 31; // must be negative
-    private static final int ABNORMAL = 1 << 18; // set atomically with DONE
-    private static final int THROWN   = 1 << 17; // set atomically with ABNORMAL
-    private static final int SIGNAL   = 1 << 16; // true if joiner waiting
-    private static final int SMASK    = 0xffff;  // short bits for tags
-
-    static boolean isExceptionalStatus(int s) {  // needed by subclasses
-        return (s & THROWN) != 0;
-    }
+    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
+    static final int NORMAL      = 0xf0000000;  // must be negative
+    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
+    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
+    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
+    static final int SMASK       = 0x0000ffff;  // short bits for tags
 
     /**
-     * Sets DONE status and wakes up threads waiting to join this task.
+     * Marks completion and wakes up threads waiting to join this
+     * task.
      *
-     * @return status on exit
+     * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
+     * @return completion status on exit
      */
-    private int setDone() {
-        int s;
-        if (((s = (int)STATUS.getAndBitwiseOr(this, DONE)) & SIGNAL) != 0)
-            synchronized (this) { notifyAll(); }
-        return s | DONE;
-    }
-
-    /**
-     * Marks cancelled or exceptional completion unless already done.
-     *
-     * @param completion must be DONE | ABNORMAL, ORed with THROWN if exceptional
-     * @return status on exit
-     */
-    private int abnormalCompletion(int completion) {
-        for (int s, ns;;) {
+    private int setCompletion(int completion) {
+        for (int s;;) {
             if ((s = status) < 0)
                 return s;
-            else if (STATUS.weakCompareAndSet(this, s, ns = s | completion)) {
-                if ((s & SIGNAL) != 0)
+            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
+                if ((s >>> 16) != 0)
                     synchronized (this) { notifyAll(); }
-                return ns;
+                return completion;
             }
         }
     }
@@ -293,11 +284,10 @@
             try {
                 completed = exec();
             } catch (Throwable rex) {
-                completed = false;
-                s = setExceptionalCompletion(rex);
+                return setExceptionalCompletion(rex);
             }
             if (completed)
-                s = setDone();
+                s = setCompletion(NORMAL);
         }
         return s;
     }
@@ -309,7 +299,9 @@
      * @param timeout using Object.wait conventions.
      */
     final void internalWait(long timeout) {
-        if ((int)STATUS.getAndBitwiseOr(this, SIGNAL) >= 0) {
+        int s;
+        if ((s = status) >= 0 && // force completer to issue notify
+            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
             synchronized (this) {
                 if (status >= 0)
                     try { wait(timeout); } catch (InterruptedException ie) { }
@@ -324,24 +316,27 @@
      * @return status upon completion
      */
     private int externalAwaitDone() {
-        int s = tryExternalHelp();
-        if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
+        int s = ((this instanceof CountedCompleter) ? // try helping
+                 ForkJoinPool.common.externalHelpComplete(
+                     (CountedCompleter<?>)this, 0) :
+                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
+        if (s >= 0 && (s = status) >= 0) {
             boolean interrupted = false;
-            synchronized (this) {
-                for (;;) {
-                    if ((s = status) >= 0) {
-                        try {
-                            wait(0L);
-                        } catch (InterruptedException ie) {
-                            interrupted = true;
+            do {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0) {
+                            try {
+                                wait(0L);
+                            } catch (InterruptedException ie) {
+                                interrupted = true;
+                            }
                         }
-                    }
-                    else {
-                        notifyAll();
-                        break;
+                        else
+                            notifyAll();
                     }
                 }
-            }
+            } while ((s = status) >= 0);
             if (interrupted)
                 Thread.currentThread().interrupt();
         }
@@ -352,40 +347,30 @@
      * Blocks a non-worker-thread until completion or interruption.
      */
     private int externalInterruptibleAwaitDone() throws InterruptedException {
-        int s = tryExternalHelp();
-        if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
-            synchronized (this) {
-                for (;;) {
-                    if ((s = status) >= 0)
-                        wait(0L);
-                    else {
-                        notifyAll();
-                        break;
+        int s;
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0 &&
+            (s = ((this instanceof CountedCompleter) ?
+                  ForkJoinPool.common.externalHelpComplete(
+                      (CountedCompleter<?>)this, 0) :
+                  ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
+                  0)) >= 0) {
+            while ((s = status) >= 0) {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0)
+                            wait(0L);
+                        else
+                            notifyAll();
                     }
                 }
             }
         }
-        else if (Thread.interrupted())
-            throw new InterruptedException();
         return s;
     }
 
     /**
-     * Tries to help with tasks allowed for external callers.
-     *
-     * @return current status
-     */
-    private int tryExternalHelp() {
-        int s;
-        return ((s = status) < 0 ? s:
-                (this instanceof CountedCompleter) ?
-                ForkJoinPool.common.externalHelpComplete(
-                    (CountedCompleter<?>)this, 0) :
-                ForkJoinPool.common.tryExternalUnpush(this) ?
-                doExec() : 0);
-    }
-
-    /**
      * Implementation for join, get, quietlyJoin. Directly handles
      * only cases of already-completed, external wait, and
      * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
@@ -419,24 +404,22 @@
     // Exception table support
 
     /**
-     * Hash table of exceptions thrown by tasks, to enable reporting
-     * by callers. Because exceptions are rare, we don't directly keep
+     * Table of exceptions thrown by tasks, to enable reporting by
+     * callers. Because exceptions are rare, we don't directly keep
      * them with task objects, but instead use a weak ref table.  Note
      * that cancellation exceptions don't appear in the table, but are
      * instead recorded as status values.
      *
-     * The exception table has a fixed capacity.
+     * Note: These statics are initialized below in static block.
      */
-    private static final ExceptionNode[] exceptionTable
-        = new ExceptionNode[32];
+    private static final ExceptionNode[] exceptionTable;
+    private static final ReentrantLock exceptionTableLock;
+    private static final ReferenceQueue<Object> exceptionTableRefQueue;
 
-    /** Lock protecting access to exceptionTable. */
-    private static final ReentrantLock exceptionTableLock
-        = new ReentrantLock();
-
-    /** Reference queue of stale exceptionally completed tasks. */
-    private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
-        = new ReferenceQueue<>();
+    /**
+     * Fixed capacity for exceptionTable.
+     */
+    private static final int EXCEPTION_MAP_CAPACITY = 32;
 
     /**
      * Key-value nodes for exception table.  The chained hash table
@@ -456,7 +439,7 @@
         final long thrower;  // use id not ref to avoid weak cycles
         final int hashCode;  // store task hashCode before weak ref disappears
         ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
-                      ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue) {
+                      ReferenceQueue<Object> exceptionTableRefQueue) {
             super(task, exceptionTableRefQueue);
             this.ex = ex;
             this.next = next;
@@ -492,7 +475,7 @@
             } finally {
                 lock.unlock();
             }
-            s = abnormalCompletion(DONE | ABNORMAL | THROWN);
+            s = setCompletion(EXCEPTIONAL);
         }
         return s;
     }
@@ -504,7 +487,7 @@
      */
     private int setExceptionalCompletion(Throwable ex) {
         int s = recordExceptionalCompletion(ex);
-        if ((s & THROWN) != 0)
+        if ((s & DONE_MASK) == EXCEPTIONAL)
             internalPropagateException(ex);
         return s;
     }
@@ -620,8 +603,9 @@
     private static void expungeStaleExceptions() {
         for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
             if (x instanceof ExceptionNode) {
+                int hashCode = ((ExceptionNode)x).hashCode;
                 ExceptionNode[] t = exceptionTable;
-                int i = ((ExceptionNode)x).hashCode & (t.length - 1);
+                int i = hashCode & (t.length - 1);
                 ExceptionNode e = t[i];
                 ExceptionNode pred = null;
                 while (e != null) {
@@ -679,8 +663,10 @@
      * Throws exception, if any, associated with the given status.
      */
     private void reportException(int s) {
-        rethrow((s & THROWN) != 0 ? getThrowableException() :
-                new CancellationException());
+        if (s == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL)
+            rethrow(getThrowableException());
     }
 
     // public methods
@@ -710,19 +696,19 @@
     }
 
     /**
-     * Returns the result of the computation when it
-     * {@linkplain #isDone is done}.
-     * This method differs from {@link #get()} in that abnormal
-     * completion results in {@code RuntimeException} or {@code Error},
-     * not {@code ExecutionException}, and that interrupts of the
-     * calling thread do <em>not</em> cause the method to abruptly
-     * return by throwing {@code InterruptedException}.
+     * Returns the result of the computation when it {@link #isDone is
+     * done}.  This method differs from {@link #get()} in that
+     * abnormal completion results in {@code RuntimeException} or
+     * {@code Error}, not {@code ExecutionException}, and that
+     * interrupts of the calling thread do <em>not</em> cause the
+     * method to abruptly return by throwing {@code
+     * InterruptedException}.
      *
      * @return the computed result
      */
     public final V join() {
         int s;
-        if (((s = doJoin()) & ABNORMAL) != 0)
+        if ((s = doJoin() & DONE_MASK) != NORMAL)
             reportException(s);
         return getRawResult();
     }
@@ -737,7 +723,7 @@
      */
     public final V invoke() {
         int s;
-        if (((s = doInvoke()) & ABNORMAL) != 0)
+        if ((s = doInvoke() & DONE_MASK) != NORMAL)
             reportException(s);
         return getRawResult();
     }
@@ -762,9 +748,9 @@
     public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
         int s1, s2;
         t2.fork();
-        if (((s1 = t1.doInvoke()) & ABNORMAL) != 0)
+        if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
             t1.reportException(s1);
-        if (((s2 = t2.doJoin()) & ABNORMAL) != 0)
+        if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
             t2.reportException(s2);
     }
 
@@ -794,7 +780,7 @@
             }
             else if (i != 0)
                 t.fork();
-            else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
+            else if (t.doInvoke() < NORMAL && ex == null)
                 ex = t.getException();
         }
         for (int i = 1; i <= last; ++i) {
@@ -802,7 +788,7 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if ((t.doJoin() & ABNORMAL) != 0)
+                else if (t.doJoin() < NORMAL)
                     ex = t.getException();
             }
         }
@@ -830,7 +816,7 @@
      */
     public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
         if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
-            invokeAll(tasks.toArray(new ForkJoinTask<?>[0]));
+            invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
             return tasks;
         }
         @SuppressWarnings("unchecked")
@@ -846,7 +832,7 @@
             }
             else if (i != 0)
                 t.fork();
-            else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
+            else if (t.doInvoke() < NORMAL && ex == null)
                 ex = t.getException();
         }
         for (int i = 1; i <= last; ++i) {
@@ -854,7 +840,7 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if ((t.doJoin() & ABNORMAL) != 0)
+                else if (t.doJoin() < NORMAL)
                     ex = t.getException();
             }
         }
@@ -891,8 +877,7 @@
      * @return {@code true} if this task is now cancelled
      */
     public boolean cancel(boolean mayInterruptIfRunning) {
-        int s = abnormalCompletion(DONE | ABNORMAL);
-        return (s & (ABNORMAL | THROWN)) == ABNORMAL;
+        return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
     }
 
     public final boolean isDone() {
@@ -900,7 +885,7 @@
     }
 
     public final boolean isCancelled() {
-        return (status & (ABNORMAL | THROWN)) == ABNORMAL;
+        return (status & DONE_MASK) == CANCELLED;
     }
 
     /**
@@ -909,7 +894,7 @@
      * @return {@code true} if this task threw an exception or was cancelled
      */
     public final boolean isCompletedAbnormally() {
-        return (status & ABNORMAL) != 0;
+        return status < NORMAL;
     }
 
     /**
@@ -920,7 +905,7 @@
      * exception and was not cancelled
      */
     public final boolean isCompletedNormally() {
-        return (status & (DONE | ABNORMAL)) == DONE;
+        return (status & DONE_MASK) == NORMAL;
     }
 
     /**
@@ -931,9 +916,9 @@
      * @return the exception, or {@code null} if none
      */
     public final Throwable getException() {
-        int s = status;
-        return ((s & ABNORMAL) == 0 ? null :
-                (s & THROWN)   == 0 ? new CancellationException() :
+        int s = status & DONE_MASK;
+        return ((s >= NORMAL)    ? null :
+                (s == CANCELLED) ? new CancellationException() :
                 getThrowableException());
     }
 
@@ -977,7 +962,7 @@
             setExceptionalCompletion(rex);
             return;
         }
-        setDone();
+        setCompletion(NORMAL);
     }
 
     /**
@@ -989,7 +974,7 @@
      * @since 1.8
      */
     public final void quietlyComplete() {
-        setDone();
+        setCompletion(NORMAL);
     }
 
     /**
@@ -1006,12 +991,11 @@
     public final V get() throws InterruptedException, ExecutionException {
         int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
             doJoin() : externalInterruptibleAwaitDone();
-        if ((s & THROWN) != 0)
-            throw new ExecutionException(getThrowableException());
-        else if ((s & ABNORMAL) != 0)
+        if ((s &= DONE_MASK) == CANCELLED)
             throw new CancellationException();
-        else
-            return getRawResult();
+        if (s == EXCEPTIONAL)
+            throw new ExecutionException(getThrowableException());
+        return getRawResult();
     }
 
     /**
@@ -1051,7 +1035,7 @@
                 while ((s = status) >= 0 &&
                        (ns = deadline - System.nanoTime()) > 0L) {
                     if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
-                        (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
+                        U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
                         synchronized (this) {
                             if (status >= 0)
                                 wait(ms); // OK to throw InterruptedException
@@ -1063,13 +1047,15 @@
             }
         }
         if (s >= 0)
-            throw new TimeoutException();
-        else if ((s & THROWN) != 0)
+            s = status;
+        if ((s &= DONE_MASK) != NORMAL) {
+            if (s == CANCELLED)
+                throw new CancellationException();
+            if (s != EXCEPTIONAL)
+                throw new TimeoutException();
             throw new ExecutionException(getThrowableException());
-        else if ((s & ABNORMAL) != 0)
-            throw new CancellationException();
-        else
-            return getRawResult();
+        }
+        return getRawResult();
     }
 
     /**
@@ -1125,7 +1111,7 @@
      * setRawResult(null)}.
      */
     public void reinitialize() {
-        if ((status & THROWN) != 0)
+        if ((status & DONE_MASK) == EXCEPTIONAL)
             clearExceptionalCompletion();
         else
             status = 0;
@@ -1343,8 +1329,8 @@
      */
     public final short setForkJoinTaskTag(short newValue) {
         for (int s;;) {
-            if (STATUS.weakCompareAndSet(this, s = status,
-                                         (s & ~SMASK) | (newValue & SMASK)))
+            if (U.compareAndSwapInt(this, STATUS, s = status,
+                                    (s & ~SMASK) | (newValue & SMASK)))
                 return (short)s;
         }
     }
@@ -1367,8 +1353,8 @@
         for (int s;;) {
             if ((short)(s = status) != expect)
                 return false;
-            if (STATUS.weakCompareAndSet(this, s,
-                                         (s & ~SMASK) | (update & SMASK)))
+            if (U.compareAndSwapInt(this, STATUS, s,
+                                    (s & ~SMASK) | (update & SMASK)))
                 return true;
         }
     }
@@ -1391,9 +1377,6 @@
         public final void setRawResult(T v) { result = v; }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + runnable + "]";
-        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1411,9 +1394,6 @@
         public final void setRawResult(Void v) { }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + runnable + "]";
-        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1459,9 +1439,6 @@
             }
         }
         public final void run() { invoke(); }
-        public String toString() {
-            return super.toString() + "[Wrapped task = " + callable + "]";
-        }
         private static final long serialVersionUID = 2838392045355241008L;
     }
 
@@ -1538,14 +1515,19 @@
             setExceptionalCompletion((Throwable)ex);
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATUS;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATUS;
+
     static {
+        exceptionTableLock = new ReentrantLock();
+        exceptionTableRefQueue = new ReferenceQueue<Object>();
+        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
+            STATUS = U.objectFieldOffset
+                (ForkJoinTask.class.getDeclaredField("status"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index fa47c22..e98ba99 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -36,8 +36,6 @@
 package java.util.concurrent;
 
 import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 
 /**
@@ -49,9 +47,7 @@
  * and termination methods surrounding the main task processing loop.
  * If you do create such a subclass, you will also need to supply a
  * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
- * {@linkplain ForkJoinPool#ForkJoinPool(int, ForkJoinWorkerThreadFactory,
- * UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit)
- * use it} in a {@code ForkJoinPool}.
+ * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
  *
  * @since 1.7
  * @author Doug Lea
@@ -70,9 +66,8 @@
      * owning thread.
      *
      * Support for (non-public) subclass InnocuousForkJoinWorkerThread
-     * requires that we break quite a lot of encapsulation (via helper
-     * methods in ThreadLocalRandom) both here and in the subclass to
-     * access and set Thread fields.
+     * requires that we break quite a lot of encapsulation (via Unsafe)
+     * both here and in the subclass to access and set Thread fields.
      */
 
     final ForkJoinPool pool;                // the pool this thread works in
@@ -92,28 +87,13 @@
     }
 
     /**
-     * Version for use by the default pool.  Supports setting the
-     * context class loader.  This is a separate constructor to avoid
-     * affecting the protected constructor.
-     */
-    ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) {
-        super("aForkJoinWorkerThread");
-        super.setContextClassLoader(ccl);
-        this.pool = pool;
-        this.workQueue = pool.registerWorker(this);
-    }
-
-    /**
      * Version for InnocuousForkJoinWorkerThread.
      */
-    ForkJoinWorkerThread(ForkJoinPool pool,
-                         ClassLoader ccl,
-                         ThreadGroup threadGroup,
+    ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
                          AccessControlContext acc) {
         super(threadGroup, null, "aForkJoinWorkerThread");
-        super.setContextClassLoader(ccl);
-        ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
-        ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
+        U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
+        eraseThreadLocals(); // clear before registering
         this.pool = pool;
         this.workQueue = pool.registerWorker(this);
     }
@@ -191,44 +171,66 @@
     }
 
     /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    final void eraseThreadLocals() {
+        U.putObject(this, THREADLOCALS, null);
+        U.putObject(this, INHERITABLETHREADLOCALS, null);
+    }
+
+    /**
      * Non-public hook method for InnocuousForkJoinWorkerThread.
      */
     void afterTopLevelExec() {
     }
 
+    // Set up to allow setting thread fields in constructor
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
+    static {
+        try {
+            THREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
     /**
      * A worker thread that has no permissions, is not a member of any
-     * user-defined ThreadGroup, uses the system class loader as
-     * thread context class loader, and erases all ThreadLocals after
+     * user-defined ThreadGroup, and erases all ThreadLocals after
      * running each top-level task.
      */
     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
         private static final ThreadGroup innocuousThreadGroup =
-            AccessController.doPrivileged(new PrivilegedAction<>() {
-                public ThreadGroup run() {
-                    ThreadGroup group = Thread.currentThread().getThreadGroup();
-                    for (ThreadGroup p; (p = group.getParent()) != null; )
-                        group = p;
-                    return new ThreadGroup(
-                        group, "InnocuousForkJoinWorkerThreadGroup");
-                }});
+            createThreadGroup();
 
         /** An AccessControlContext supporting no privileges */
         private static final AccessControlContext INNOCUOUS_ACC =
             new AccessControlContext(
-                new ProtectionDomain[] { new ProtectionDomain(null, null) });
+                new ProtectionDomain[] {
+                    new ProtectionDomain(null, null)
+                });
 
         InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
-            super(pool,
-                  ClassLoader.getSystemClassLoader(),
-                  innocuousThreadGroup,
-                  INNOCUOUS_ACC);
+            super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
         }
 
         @Override // to erase ThreadLocals
         void afterTopLevelExec() {
-            ThreadLocalRandom.eraseThreadLocals(this);
+            eraseThreadLocals();
+        }
+
+        @Override // to always report system loader
+        public ClassLoader getContextClassLoader() {
+            return ClassLoader.getSystemClassLoader();
         }
 
         @Override // to silently fail
@@ -238,5 +240,34 @@
         public void setContextClassLoader(ClassLoader cl) {
             throw new SecurityException("setContextClassLoader");
         }
+
+        /**
+         * Returns a new group with the system ThreadGroup (the
+         * topmost, parent-less group) as parent.  Uses Unsafe to
+         * traverse Thread.group and ThreadGroup.parent fields.
+         */
+        private static ThreadGroup createThreadGroup() {
+            try {
+                sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
+                long tg = u.objectFieldOffset
+                    (Thread.class.getDeclaredField("group"));
+                long gp = u.objectFieldOffset
+                    (ThreadGroup.class.getDeclaredField("parent"));
+                ThreadGroup group = (ThreadGroup)
+                    u.getObject(Thread.currentThread(), tg);
+                while (group != null) {
+                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
+                    if (parent == null)
+                        return new ThreadGroup(group,
+                                               "InnocuousForkJoinWorkerThreadGroup");
+                    group = parent;
+                }
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+            // fall through if null as cannot-happen safeguard
+            throw new Error("Cannot create ThreadGroup");
+        }
     }
+
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/Future.java b/ojluni/src/main/java/java/util/concurrent/Future.java
index 6099c7c..9bd05d6 100644
--- a/ojluni/src/main/java/java/util/concurrent/Future.java
+++ b/ojluni/src/main/java/java/util/concurrent/Future.java
@@ -50,7 +50,8 @@
  * declare types of the form {@code Future<?>} and
  * return {@code null} as a result of the underlying task.
  *
- * <p><b>Sample Usage</b> (Note that the following classes are all
+ * <p>
+ * <b>Sample Usage</b> (Note that the following classes are all
  * made-up.)
  *
  * <pre> {@code
@@ -58,9 +59,13 @@
  * class App {
  *   ExecutorService executor = ...
  *   ArchiveSearcher searcher = ...
- *   void showSearch(String target) throws InterruptedException {
- *     Callable<String> task = () -> searcher.search(target);
- *     Future<String> future = executor.submit(task);
+ *   void showSearch(final String target)
+ *       throws InterruptedException {
+ *     Future<String> future
+ *       = executor.submit(new Callable<String>() {
+ *         public String call() {
+ *             return searcher.search(target);
+ *         }});
  *     displayOtherThings(); // do other things while searching
  *     try {
  *       displayText(future.get()); // use future
@@ -72,7 +77,11 @@
  * implements {@code Runnable}, and so may be executed by an {@code Executor}.
  * For example, the above construction with {@code submit} could be replaced by:
  * <pre> {@code
- * FutureTask<String> future = new FutureTask<>(task);
+ * FutureTask<String> future =
+ *   new FutureTask<>(new Callable<String>() {
+ *     public String call() {
+ *       return searcher.search(target);
+ *   }});
  * executor.execute(future);}</pre>
  *
  * <p>Memory consistency effects: Actions taken by the asynchronous computation
diff --git a/ojluni/src/main/java/java/util/concurrent/FutureTask.java b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
index e913ef3..62c2bfc 100644
--- a/ojluni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -71,6 +69,9 @@
      * cancellation races. Sync control in the current design relies
      * on a "state" field updated via CAS to track completion, along
      * with a simple Treiber stack to hold waiting threads.
+     *
+     * Style note: As usual, we bypass overhead of using
+     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
      */
 
     /**
@@ -162,8 +163,9 @@
     }
 
     public boolean cancel(boolean mayInterruptIfRunning) {
-        if (!(state == NEW && STATE.compareAndSet
-              (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+        if (!(state == NEW &&
+              U.compareAndSwapInt(this, STATE, NEW,
+                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
             return false;
         try {    // in case call to interrupt throws exception
             if (mayInterruptIfRunning) {
@@ -172,7 +174,7 @@
                     if (t != null)
                         t.interrupt();
                 } finally { // final state
-                    STATE.setRelease(this, INTERRUPTED);
+                    U.putOrderedInt(this, STATE, INTERRUPTED);
                 }
             }
         } finally {
@@ -226,9 +228,9 @@
      * @param v the value
      */
     protected void set(V v) {
-        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
             outcome = v;
-            STATE.setRelease(this, NORMAL); // final state
+            U.putOrderedInt(this, STATE, NORMAL); // final state
             finishCompletion();
         }
     }
@@ -244,16 +246,16 @@
      * @param t the cause of failure
      */
     protected void setException(Throwable t) {
-        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
             outcome = t;
-            STATE.setRelease(this, EXCEPTIONAL); // final state
+            U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
             finishCompletion();
         }
     }
 
     public void run() {
         if (state != NEW ||
-            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
             return;
         try {
             Callable<V> c = callable;
@@ -294,7 +296,7 @@
      */
     protected boolean runAndReset() {
         if (state != NEW ||
-            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
             return false;
         boolean ran = false;
         int s = state;
@@ -361,7 +363,7 @@
     private void finishCompletion() {
         // assert state > COMPLETING;
         for (WaitNode q; (q = waiters) != null;) {
-            if (WAITERS.weakCompareAndSet(this, q, null)) {
+            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
                 for (;;) {
                     Thread t = q.thread;
                     if (t != null) {
@@ -423,7 +425,8 @@
                 q = new WaitNode();
             }
             else if (!queued)
-                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
+                queued = U.compareAndSwapObject(this, WAITERS,
+                                                q.next = waiters, q);
             else if (timed) {
                 final long parkNanos;
                 if (startTime == 0L) { // first time
@@ -472,7 +475,7 @@
                         if (pred.thread == null) // check for race
                             continue retry;
                     }
-                    else if (!WAITERS.compareAndSet(this, q, s))
+                    else if (!U.compareAndSwapObject(this, WAITERS, q, s))
                         continue retry;
                 }
                 break;
@@ -480,53 +483,21 @@
         }
     }
 
-    /**
-     * Returns a string representation of this FutureTask.
-     *
-     * @implSpec
-     * The default implementation returns a string identifying this
-     * FutureTask, as well as its completion state.  The state, in
-     * brackets, contains one of the strings {@code "Completed Normally"},
-     * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
-     * "Not completed"}.
-     *
-     * @return a string representation of this FutureTask
-     */
-    public String toString() {
-        final String status;
-        switch (state) {
-        case NORMAL:
-            status = "[Completed normally]";
-            break;
-        case EXCEPTIONAL:
-            status = "[Completed exceptionally: " + outcome + "]";
-            break;
-        case CANCELLED:
-        case INTERRUPTING:
-        case INTERRUPTED:
-            status = "[Cancelled]";
-            break;
-        default:
-            final Callable<?> callable = this.callable;
-            status = (callable == null)
-                ? "[Not completed]"
-                : "[Not completed, task = " + callable + "]";
-        }
-        return super.toString() + status;
-    }
-
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle RUNNER;
-    private static final VarHandle WAITERS;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long RUNNER;
+    private static final long WAITERS;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(FutureTask.class, "state", int.class);
-            RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
-            WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
+            STATE = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("state"));
+            RUNNER = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("runner"));
+            WAITERS = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("waiters"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
index f55998e..9829c9c 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -39,13 +39,15 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
@@ -64,12 +66,9 @@
  * contains}, {@link #iterator iterator.remove()}, and the bulk
  * operations, all of which run in linear time.
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
- *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
  *
  * @since 1.6
  * @author  Doug Lea
@@ -195,7 +194,18 @@
      */
     public LinkedBlockingDeque(Collection<? extends E> c) {
         this(Integer.MAX_VALUE);
-        addAll(c);
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Never contended, but necessary for visibility
+        try {
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (!linkLast(new Node<E>(e)))
+                    throw new IllegalStateException("Deque full");
+            }
+        } finally {
+            lock.unlock();
+        }
     }
 
 
@@ -288,7 +298,6 @@
      */
     void unlink(Node<E> x) {
         // assert lock.isHeldByCurrentThread();
-        // assert x.item != null;
         Node<E> p = x.prev;
         Node<E> n = x.next;
         if (p == null) {
@@ -651,7 +660,7 @@
 
     /**
      * Retrieves and removes the head of the queue represented by this deque.
-     * This method differs from {@link #poll() poll()} only in that it throws an
+     * This method differs from {@link #poll poll} only in that it throws an
      * exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -677,7 +686,7 @@
 
     /**
      * Retrieves, but does not remove, the head of the queue represented by
-     * this deque.  This method differs from {@link #peek() peek()} only in that
+     * this deque.  This method differs from {@link #peek peek} only in that
      * it throws an exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -731,7 +740,8 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -824,65 +834,46 @@
         }
     }
 
-    /**
-     * Appends all of the elements in the specified collection to the end of
-     * this deque, in the order that they are returned by the specified
-     * collection's iterator.  Attempts to {@code addAll} of a deque to
-     * itself result in {@code IllegalArgumentException}.
+    /*
+     * TODO: Add support for more efficient bulk operations.
      *
-     * @param c the elements to be inserted into this deque
-     * @return {@code true} if this deque changed as a result of the call
-     * @throws NullPointerException if the specified collection or any
-     *         of its elements are null
-     * @throws IllegalArgumentException if the collection is this deque
-     * @throws IllegalStateException if this deque is full
-     * @see #add(Object)
+     * We don't want to acquire the lock for every iteration, but we
+     * also want other threads a chance to interact with the
+     * collection, especially when count is close to capacity.
      */
-    public boolean addAll(Collection<? extends E> c) {
-        if (c == this)
-            // As historically specified in AbstractQueue#addAll
-            throw new IllegalArgumentException();
 
-        // Copy c into a private chain of Nodes
-        Node<E> beg = null, end = null;
-        int n = 0;
-        for (E e : c) {
-            Objects.requireNonNull(e);
-            n++;
-            Node<E> newNode = new Node<E>(e);
-            if (beg == null)
-                beg = end = newNode;
-            else {
-                end.next = newNode;
-                newNode.prev = end;
-                end = newNode;
-            }
-        }
-        if (beg == null)
-            return false;
-
-        // Atomically append the chain at the end
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            if (count + n <= capacity) {
-                beg.prev = last;
-                if (first == null)
-                    first = beg;
-                else
-                    last.next = beg;
-                last = end;
-                count += n;
-                notEmpty.signalAll();
-                return true;
-            }
-        } finally {
-            lock.unlock();
-        }
-        // Fall back to historic non-atomic implementation, failing
-        // with IllegalStateException when the capacity is exceeded.
-        return super.addAll(c);
-    }
+//     /**
+//      * Adds all of the elements in the specified collection to this
+//      * queue.  Attempts to addAll of a queue to itself result in
+//      * {@code IllegalArgumentException}. Further, the behavior of
+//      * this operation is undefined if the specified collection is
+//      * modified while the operation is in progress.
+//      *
+//      * @param c collection containing elements to be added to this queue
+//      * @return {@code true} if this queue changed as a result of the call
+//      * @throws ClassCastException            {@inheritDoc}
+//      * @throws NullPointerException          {@inheritDoc}
+//      * @throws IllegalArgumentException      {@inheritDoc}
+//      * @throws IllegalStateException if this deque is full
+//      * @see #add(Object)
+//      */
+//     public boolean addAll(Collection<? extends E> c) {
+//         if (c == null)
+//             throw new NullPointerException();
+//         if (c == this)
+//             throw new IllegalArgumentException();
+//         final ReentrantLock lock = this.lock;
+//         lock.lock();
+//         try {
+//             boolean modified = false;
+//             for (E e : c)
+//                 if (linkLast(e))
+//                     modified = true;
+//             return modified;
+//         } finally {
+//             lock.unlock();
+//         }
+//     }
 
     /**
      * Returns an array containing all of the elements in this deque, in
@@ -995,18 +986,6 @@
     }
 
     /**
-     * Used for any element traversal that is not entirely under lock.
-     * Such traversals must handle both:
-     * - dequeued nodes (p.next == p)
-     * - (possibly multiple) interior removed nodes (p.item == null)
-     */
-    Node<E> succ(Node<E> p) {
-        if (p == (p = p.next))
-            p = first;
-        return p;
-    }
-
-    /**
      * Returns an iterator over the elements in this deque in proper sequence.
      * The elements will be returned in order from first (head) to last (tail).
      *
@@ -1045,8 +1024,8 @@
         /**
          * nextItem holds on to item fields because once we claim that
          * an element exists in hasNext(), we must return item read
-         * under lock even if it was in the process of being removed
-         * when hasNext() was called.
+         * under lock (in advance()) even if it was in the process of
+         * being removed when hasNext() was called.
          */
         E nextItem;
 
@@ -1059,19 +1038,48 @@
         abstract Node<E> firstNode();
         abstract Node<E> nextNode(Node<E> n);
 
-        private Node<E> succ(Node<E> p) {
-            if (p == (p = nextNode(p)))
-                p = firstNode();
-            return p;
-        }
-
         AbstractItr() {
             // set to initial position
             final ReentrantLock lock = LinkedBlockingDeque.this.lock;
             lock.lock();
             try {
-                if ((next = firstNode()) != null)
-                    nextItem = next.item;
+                next = firstNode();
+                nextItem = (next == null) ? null : next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Returns the successor node of the given non-null, but
+         * possibly previously deleted, node.
+         */
+        private Node<E> succ(Node<E> n) {
+            // Chains of deleted nodes ending in null or self-links
+            // are possible if multiple interior nodes are removed.
+            for (;;) {
+                Node<E> s = nextNode(n);
+                if (s == null)
+                    return null;
+                else if (s.item != null)
+                    return s;
+                else if (s == n)
+                    return firstNode();
+                else
+                    n = s;
+            }
+        }
+
+        /**
+         * Advances next.
+         */
+        void advance() {
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                // assert next != null;
+                next = succ(next);
+                nextItem = (next == null) ? null : next.item;
             } finally {
                 lock.unlock();
             }
@@ -1082,65 +1090,14 @@
         }
 
         public E next() {
-            Node<E> p;
-            if ((p = next) == null)
+            if (next == null)
                 throw new NoSuchElementException();
-            lastRet = p;
+            lastRet = next;
             E x = nextItem;
-            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
-            lock.lock();
-            try {
-                E e = null;
-                for (p = nextNode(p); p != null && (e = p.item) == null; )
-                    p = succ(p);
-                next = p;
-                nextItem = e;
-            } finally {
-                lock.unlock();
-            }
+            advance();
             return x;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            // A variant of forEachFrom
-            Objects.requireNonNull(action);
-            Node<E> p;
-            if ((p = next) == null) return;
-            lastRet = p;
-            next = null;
-            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
-            final int batchSize = 64;
-            Object[] es = null;
-            int n, len = 1;
-            do {
-                lock.lock();
-                try {
-                    if (es == null) {
-                        p = nextNode(p);
-                        for (Node<E> q = p; q != null; q = succ(q))
-                            if (q.item != null && ++len == batchSize)
-                                break;
-                        es = new Object[len];
-                        es[0] = nextItem;
-                        nextItem = null;
-                        n = 1;
-                    } else
-                        n = 0;
-                    for (; p != null && n < len; p = succ(p))
-                        if ((es[n] = p.item) != null) {
-                            lastRet = p;
-                            n++;
-                        }
-                } finally {
-                    lock.unlock();
-                }
-                for (int i = 0; i < n; i++) {
-                    @SuppressWarnings("unchecked") E e = (E) es[i];
-                    action.accept(e);
-                }
-            } while (n > 0 && p != null);
-        }
-
         public void remove() {
             Node<E> n = lastRet;
             if (n == null)
@@ -1159,49 +1116,51 @@
 
     /** Forward iterator */
     private class Itr extends AbstractItr {
-        Itr() {}                        // prevent access constructor creation
         Node<E> firstNode() { return first; }
         Node<E> nextNode(Node<E> n) { return n.next; }
     }
 
     /** Descending iterator */
     private class DescendingItr extends AbstractItr {
-        DescendingItr() {}              // prevent access constructor creation
         Node<E> firstNode() { return last; }
         Node<E> nextNode(Node<E> n) { return n.prev; }
     }
 
-    /**
-     * A customized variant of Spliterators.IteratorSpliterator.
-     * Keep this class in sync with (very similar) LBQSpliterator.
-     */
-    private final class LBDSpliterator implements Spliterator<E> {
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBDSpliterator<E> implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        long est = size();  // size estimate
-
-        LBDSpliterator() {}
+        long est;           // size estimate
+        LBDSpliterator(LinkedBlockingDeque<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
+            final LinkedBlockingDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = first) != null)
-                && h.next != null) {
-                int n = batch = Math.min(batch + 1, MAX_BATCH);
+                ((h = current) != null || (h = q.first) != null) &&
+                h.next != null) {
                 Object[] a = new Object[n];
-                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+                final ReentrantLock lock = q.lock;
                 int i = 0;
                 Node<E> p = current;
                 lock.lock();
                 try {
-                    if (p != null || (p = first) != null)
-                        for (; p != null && i < n; p = succ(p))
+                    if (p != null || (p = q.first) != null) {
+                        do {
                             if ((a[i] = p.item) != null)
-                                i++;
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
                 } finally {
                     lock.unlock();
                 }
@@ -1211,33 +1170,66 @@
                 }
                 else if ((est -= i) < 0L)
                     est = 0L;
-                if (i > 0)
+                if (i > 0) {
+                    batch = i;
                     return Spliterators.spliterator
                         (a, 0, i, (Spliterator.ORDERED |
                                    Spliterator.NONNULL |
                                    Spliterator.CONCURRENT));
+                }
             }
             return null;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    lock.lock();
+                    try {
+                        if (p == null)
+                            p = q.first;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        lock.unlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
             if (!exhausted) {
                 E e = null;
-                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
                 lock.lock();
                 try {
-                    Node<E> p;
-                    if ((p = current) != null || (p = first) != null)
-                        do {
-                            e = p.item;
-                            p = succ(p);
-                        } while (e == null && p != null);
-                    if ((current = p) == null)
-                        exhausted = true;
+                    if (current == null)
+                        current = q.first;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
                 } finally {
                     lock.unlock();
                 }
+                if (current == null)
+                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -1246,20 +1238,9 @@
             return false;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                current = null;
-                forEachFrom(action, p);
-            }
-        }
-
         public int characteristics() {
-            return (Spliterator.ORDERED |
-                    Spliterator.NONNULL |
-                    Spliterator.CONCURRENT);
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
         }
     }
 
@@ -1280,127 +1261,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBDSpliterator();
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        forEachFrom(action, null);
-    }
-
-    /**
-     * Runs action on each element found during a traversal starting at p.
-     * If p is null, traversal starts at head.
-     */
-    void forEachFrom(Consumer<? super E> action, Node<E> p) {
-        // Extract batches of elements while holding the lock; then
-        // run the action on the elements while not
-        final ReentrantLock lock = this.lock;
-        final int batchSize = 64;       // max number of elements per batch
-        Object[] es = null;             // container for batch of elements
-        int n, len = 0;
-        do {
-            lock.lock();
-            try {
-                if (es == null) {
-                    if (p == null) p = first;
-                    for (Node<E> q = p; q != null; q = succ(q))
-                        if (q.item != null && ++len == batchSize)
-                            break;
-                    es = new Object[len];
-                }
-                for (n = 0; p != null && n < len; p = succ(p))
-                    if ((es[n] = p.item) != null)
-                        n++;
-            } finally {
-                lock.unlock();
-            }
-            for (int i = 0; i < n; i++) {
-                @SuppressWarnings("unchecked") E e = (E) es[i];
-                action.accept(e);
-            }
-        } while (n > 0 && p != null);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
-
-    /** Implementation of bulk remove methods. */
-    @SuppressWarnings("unchecked")
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        boolean removed = false;
-        final ReentrantLock lock = this.lock;
-        Node<E> p = null;
-        Node<E>[] nodes = null;
-        int n, len = 0;
-        do {
-            // 1. Extract batch of up to 64 elements while holding the lock.
-            lock.lock();
-            try {
-                if (nodes == null) {  // first batch; initialize
-                    p = first;
-                    for (Node<E> q = p; q != null; q = succ(q))
-                        if (q.item != null && ++len == 64)
-                            break;
-                    nodes = (Node<E>[]) new Node<?>[len];
-                }
-                for (n = 0; p != null && n < len; p = succ(p))
-                    nodes[n++] = p;
-            } finally {
-                lock.unlock();
-            }
-
-            // 2. Run the filter on the elements while lock is free.
-            long deathRow = 0L;       // "bitset" of size 64
-            for (int i = 0; i < n; i++) {
-                final E e;
-                if ((e = nodes[i].item) != null && filter.test(e))
-                    deathRow |= 1L << i;
-            }
-
-            // 3. Remove any filtered elements while holding the lock.
-            if (deathRow != 0) {
-                lock.lock();
-                try {
-                    for (int i = 0; i < n; i++) {
-                        final Node<E> q;
-                        if ((deathRow & (1L << i)) != 0L
-                            && (q = nodes[i]).item != null) {
-                            unlink(q);
-                            removed = true;
-                        }
-                        nodes[i] = null; // help GC
-                    }
-                } finally {
-                    lock.unlock();
-                }
-            }
-        } while (n > 0 && p != null);
-        return removed;
+        return new LBDSpliterator<E>(this);
     }
 
     /**
@@ -1443,21 +1304,12 @@
         last = null;
         // Read in all elements and place in queue
         for (;;) {
-            @SuppressWarnings("unchecked") E item = (E)s.readObject();
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
             if (item == null)
                 break;
             add(item);
         }
     }
 
-    void checkInvariants() {
-        // assert lock.isHeldByCurrentThread();
-        // Nodes may get self-linked or lose their item, but only
-        // after being unlinked and becoming unreachable from first.
-        for (Node<E> p = first; p != null; p = p.next) {
-            // assert p.next != p;
-            // assert p.item != null;
-        }
-    }
-
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index 4ba6c1e..cf2d447 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -39,14 +39,16 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
@@ -67,12 +69,9 @@
  * dynamically created upon each insertion unless this would bring the
  * queue above capacity.
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
- *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
  *
  * @since 1.5
  * @author Doug Lea
@@ -235,6 +234,14 @@
         putLock.unlock();
     }
 
+//     /**
+//      * Tells whether both locks are held by current thread.
+//      */
+//     boolean isFullyLocked() {
+//         return (putLock.isHeldByCurrentThread() &&
+//                 takeLock.isHeldByCurrentThread());
+//     }
+
     /**
      * Creates a {@code LinkedBlockingQueue} with a capacity of
      * {@link Integer#MAX_VALUE}.
@@ -323,8 +330,10 @@
      */
     public void put(E e) throws InterruptedException {
         if (e == null) throw new NullPointerException();
-        final int c;
-        final Node<E> node = new Node<E>(e);
+        // Note: convention in all put/take/etc is to preset local var
+        // holding count negative to indicate failure unless set.
+        int c = -1;
+        Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         final AtomicInteger count = this.count;
         putLock.lockInterruptibly();
@@ -365,7 +374,7 @@
 
         if (e == null) throw new NullPointerException();
         long nanos = unit.toNanos(timeout);
-        final int c;
+        int c = -1;
         final ReentrantLock putLock = this.putLock;
         final AtomicInteger count = this.count;
         putLock.lockInterruptibly();
@@ -403,28 +412,28 @@
         final AtomicInteger count = this.count;
         if (count.get() == capacity)
             return false;
-        final int c;
-        final Node<E> node = new Node<E>(e);
+        int c = -1;
+        Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         putLock.lock();
         try {
-            if (count.get() == capacity)
-                return false;
-            enqueue(node);
-            c = count.getAndIncrement();
-            if (c + 1 < capacity)
-                notFull.signal();
+            if (count.get() < capacity) {
+                enqueue(node);
+                c = count.getAndIncrement();
+                if (c + 1 < capacity)
+                    notFull.signal();
+            }
         } finally {
             putLock.unlock();
         }
         if (c == 0)
             signalNotEmpty();
-        return true;
+        return c >= 0;
     }
 
     public E take() throws InterruptedException {
-        final E x;
-        final int c;
+        E x;
+        int c = -1;
         final AtomicInteger count = this.count;
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lockInterruptibly();
@@ -445,8 +454,8 @@
     }
 
     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
-        final E x;
-        final int c;
+        E x = null;
+        int c = -1;
         long nanos = unit.toNanos(timeout);
         final AtomicInteger count = this.count;
         final ReentrantLock takeLock = this.takeLock;
@@ -473,17 +482,17 @@
         final AtomicInteger count = this.count;
         if (count.get() == 0)
             return null;
-        final E x;
-        final int c;
+        E x = null;
+        int c = -1;
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lock();
         try {
-            if (count.get() == 0)
-                return null;
-            x = dequeue();
-            c = count.getAndDecrement();
-            if (c > 1)
-                notEmpty.signal();
+            if (count.get() > 0) {
+                x = dequeue();
+                c = count.getAndDecrement();
+                if (c > 1)
+                    notEmpty.signal();
+            }
         } finally {
             takeLock.unlock();
         }
@@ -493,7 +502,6 @@
     }
 
     public E peek() {
-        final AtomicInteger count = this.count;
         if (count.get() == 0)
             return null;
         final ReentrantLock takeLock = this.takeLock;
@@ -506,17 +514,16 @@
     }
 
     /**
-     * Unlinks interior Node p with predecessor pred.
+     * Unlinks interior Node p with predecessor trail.
      */
-    void unlink(Node<E> p, Node<E> pred) {
-        // assert putLock.isHeldByCurrentThread();
-        // assert takeLock.isHeldByCurrentThread();
+    void unlink(Node<E> p, Node<E> trail) {
+        // assert isFullyLocked();
         // p.next is not changed, to allow iterators that are
         // traversing p to maintain their weak-consistency guarantee.
         p.item = null;
-        pred.next = p.next;
+        trail.next = p.next;
         if (last == p)
-            last = pred;
+            last = trail;
         if (count.getAndDecrement() == capacity)
             notFull.signal();
     }
@@ -536,11 +543,11 @@
         if (o == null) return false;
         fullyLock();
         try {
-            for (Node<E> pred = head, p = pred.next;
+            for (Node<E> trail = head, p = trail.next;
                  p != null;
-                 pred = p, p = p.next) {
+                 trail = p, p = p.next) {
                 if (o.equals(p.item)) {
-                    unlink(p, pred);
+                    unlink(p, trail);
                     return true;
                 }
             }
@@ -694,7 +701,8 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -733,18 +741,6 @@
     }
 
     /**
-     * Used for any element traversal that is not entirely under lock.
-     * Such traversals must handle both:
-     * - dequeued nodes (p.next == p)
-     * - (possibly multiple) interior removed nodes (p.item == null)
-     */
-    Node<E> succ(Node<E> p) {
-        if (p == (p = p.next))
-            p = head.next;
-        return p;
-    }
-
-    /**
      * Returns an iterator over the elements in this queue in proper sequence.
      * The elements will be returned in order from first (head) to last (tail).
      *
@@ -757,103 +753,71 @@
         return new Itr();
     }
 
-    /**
-     * Weakly-consistent iterator.
-     *
-     * Lazily updated ancestor field provides expected O(1) remove(),
-     * but still O(n) in the worst case, whenever the saved ancestor
-     * is concurrently deleted.
-     */
     private class Itr implements Iterator<E> {
-        private Node<E> next;           // Node holding nextItem
-        private E nextItem;             // next item to hand out
+        /*
+         * Basic weakly-consistent iterator.  At all times hold the next
+         * item to hand out so that if hasNext() reports true, we will
+         * still have it to return even if lost race with a take etc.
+         */
+
+        private Node<E> current;
         private Node<E> lastRet;
-        private Node<E> ancestor;       // Helps unlink lastRet on remove()
+        private E currentElement;
 
         Itr() {
             fullyLock();
             try {
-                if ((next = head.next) != null)
-                    nextItem = next.item;
+                current = head.next;
+                if (current != null)
+                    currentElement = current.item;
             } finally {
                 fullyUnlock();
             }
         }
 
         public boolean hasNext() {
-            return next != null;
+            return current != null;
         }
 
         public E next() {
-            Node<E> p;
-            if ((p = next) == null)
-                throw new NoSuchElementException();
-            lastRet = p;
-            E x = nextItem;
             fullyLock();
             try {
-                E e = null;
-                for (p = p.next; p != null && (e = p.item) == null; )
-                    p = succ(p);
-                next = p;
-                nextItem = e;
+                if (current == null)
+                    throw new NoSuchElementException();
+                lastRet = current;
+                E item = null;
+                // Unlike other traversal methods, iterators must handle both:
+                // - dequeued nodes (p.next == p)
+                // - (possibly multiple) interior removed nodes (p.item == null)
+                for (Node<E> p = current, q;; p = q) {
+                    if ((q = p.next) == p)
+                        q = head.next;
+                    if (q == null || (item = q.item) != null) {
+                        current = q;
+                        E x = currentElement;
+                        currentElement = item;
+                        return x;
+                    }
+                }
             } finally {
                 fullyUnlock();
             }
-            return x;
-        }
-
-        public void forEachRemaining(Consumer<? super E> action) {
-            // A variant of forEachFrom
-            Objects.requireNonNull(action);
-            Node<E> p;
-            if ((p = next) == null) return;
-            lastRet = p;
-            next = null;
-            final int batchSize = 64;
-            Object[] es = null;
-            int n, len = 1;
-            do {
-                fullyLock();
-                try {
-                    if (es == null) {
-                        p = p.next;
-                        for (Node<E> q = p; q != null; q = succ(q))
-                            if (q.item != null && ++len == batchSize)
-                                break;
-                        es = new Object[len];
-                        es[0] = nextItem;
-                        nextItem = null;
-                        n = 1;
-                    } else
-                        n = 0;
-                    for (; p != null && n < len; p = succ(p))
-                        if ((es[n] = p.item) != null) {
-                            lastRet = p;
-                            n++;
-                        }
-                } finally {
-                    fullyUnlock();
-                }
-                for (int i = 0; i < n; i++) {
-                    @SuppressWarnings("unchecked") E e = (E) es[i];
-                    action.accept(e);
-                }
-            } while (n > 0 && p != null);
         }
 
         public void remove() {
-            Node<E> p = lastRet;
-            if (p == null)
+            if (lastRet == null)
                 throw new IllegalStateException();
-            lastRet = null;
             fullyLock();
             try {
-                if (p.item != null) {
-                    if (ancestor == null)
-                        ancestor = head;
-                    ancestor = findPred(p, ancestor);
-                    unlink(p, ancestor);
+                Node<E> node = lastRet;
+                lastRet = null;
+                for (Node<E> trail = head, p = trail.next;
+                     p != null;
+                     trail = p, p = p.next) {
+                    if (p == node) {
+                        unlink(p, trail);
+                        break;
+                    }
                 }
             } finally {
                 fullyUnlock();
@@ -861,38 +825,42 @@
         }
     }
 
-    /**
-     * A customized variant of Spliterators.IteratorSpliterator.
-     * Keep this class in sync with (very similar) LBDSpliterator.
-     */
-    private final class LBQSpliterator implements Spliterator<E> {
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBQSpliterator<E> implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingQueue<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        long est = size();  // size estimate
-
-        LBQSpliterator() {}
+        long est;           // size estimate
+        LBQSpliterator(LinkedBlockingQueue<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
+            final LinkedBlockingQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = head.next) != null)
-                && h.next != null) {
-                int n = batch = Math.min(batch + 1, MAX_BATCH);
+                ((h = current) != null || (h = q.head.next) != null) &&
+                h.next != null) {
                 Object[] a = new Object[n];
                 int i = 0;
                 Node<E> p = current;
-                fullyLock();
+                q.fullyLock();
                 try {
-                    if (p != null || (p = head.next) != null)
-                        for (; p != null && i < n; p = succ(p))
+                    if (p != null || (p = q.head.next) != null) {
+                        do {
                             if ((a[i] = p.item) != null)
-                                i++;
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
                 } finally {
-                    fullyUnlock();
+                    q.fullyUnlock();
                 }
                 if ((current = p) == null) {
                     est = 0L;
@@ -900,32 +868,64 @@
                 }
                 else if ((est -= i) < 0L)
                     est = 0L;
-                if (i > 0)
+                if (i > 0) {
+                    batch = i;
                     return Spliterators.spliterator
                         (a, 0, i, (Spliterator.ORDERED |
                                    Spliterator.NONNULL |
                                    Spliterator.CONCURRENT));
+                }
             }
             return null;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    q.fullyLock();
+                    try {
+                        if (p == null)
+                            p = q.head.next;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        q.fullyUnlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
             if (!exhausted) {
                 E e = null;
-                fullyLock();
+                q.fullyLock();
                 try {
-                    Node<E> p;
-                    if ((p = current) != null || (p = head.next) != null)
-                        do {
-                            e = p.item;
-                            p = succ(p);
-                        } while (e == null && p != null);
-                    if ((current = p) == null)
-                        exhausted = true;
+                    if (current == null)
+                        current = q.head.next;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
                 } finally {
-                    fullyUnlock();
+                    q.fullyUnlock();
                 }
+                if (current == null)
+                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -934,20 +934,9 @@
             return false;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                current = null;
-                forEachFrom(action, p);
-            }
-        }
-
         public int characteristics() {
-            return (Spliterator.ORDERED |
-                    Spliterator.NONNULL |
-                    Spliterator.CONCURRENT);
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
         }
     }
 
@@ -968,140 +957,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBQSpliterator();
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        forEachFrom(action, null);
-    }
-
-    /**
-     * Runs action on each element found during a traversal starting at p.
-     * If p is null, traversal starts at head.
-     */
-    void forEachFrom(Consumer<? super E> action, Node<E> p) {
-        // Extract batches of elements while holding the lock; then
-        // run the action on the elements while not
-        final int batchSize = 64;       // max number of elements per batch
-        Object[] es = null;             // container for batch of elements
-        int n, len = 0;
-        do {
-            fullyLock();
-            try {
-                if (es == null) {
-                    if (p == null) p = head.next;
-                    for (Node<E> q = p; q != null; q = succ(q))
-                        if (q.item != null && ++len == batchSize)
-                            break;
-                    es = new Object[len];
-                }
-                for (n = 0; p != null && n < len; p = succ(p))
-                    if ((es[n] = p.item) != null)
-                        n++;
-            } finally {
-                fullyUnlock();
-            }
-            for (int i = 0; i < n; i++) {
-                @SuppressWarnings("unchecked") E e = (E) es[i];
-                action.accept(e);
-            }
-        } while (n > 0 && p != null);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
-
-    /**
-     * Returns the predecessor of live node p, given a node that was
-     * once a live ancestor of p (or head); allows unlinking of p.
-     */
-    Node<E> findPred(Node<E> p, Node<E> ancestor) {
-        // assert p.item != null;
-        if (ancestor.item == null)
-            ancestor = head;
-        // Fails with NPE if precondition not satisfied
-        for (Node<E> q; (q = ancestor.next) != p; )
-            ancestor = q;
-        return ancestor;
-    }
-
-    /** Implementation of bulk remove methods. */
-    @SuppressWarnings("unchecked")
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        boolean removed = false;
-        Node<E> p = null, ancestor = head;
-        Node<E>[] nodes = null;
-        int n, len = 0;
-        do {
-            // 1. Extract batch of up to 64 elements while holding the lock.
-            fullyLock();
-            try {
-                if (nodes == null) {  // first batch; initialize
-                    p = head.next;
-                    for (Node<E> q = p; q != null; q = succ(q))
-                        if (q.item != null && ++len == 64)
-                            break;
-                    nodes = (Node<E>[]) new Node<?>[len];
-                }
-                for (n = 0; p != null && n < len; p = succ(p))
-                    nodes[n++] = p;
-            } finally {
-                fullyUnlock();
-            }
-
-            // 2. Run the filter on the elements while lock is free.
-            long deathRow = 0L;       // "bitset" of size 64
-            for (int i = 0; i < n; i++) {
-                final E e;
-                if ((e = nodes[i].item) != null && filter.test(e))
-                    deathRow |= 1L << i;
-            }
-
-            // 3. Remove any filtered elements while holding the lock.
-            if (deathRow != 0) {
-                fullyLock();
-                try {
-                    for (int i = 0; i < n; i++) {
-                        final Node<E> q;
-                        if ((deathRow & (1L << i)) != 0L
-                            && (q = nodes[i]).item != null) {
-                            ancestor = findPred(q, ancestor);
-                            unlink(q, ancestor);
-                            removed = true;
-                        }
-                        nodes[i] = null; // help GC
-                    }
-                } finally {
-                    fullyUnlock();
-                }
-            }
-        } while (n > 0 && p != null);
-        return removed;
+        return new LBQSpliterator<E>(this);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index 06d04e22..e282b42 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -35,20 +35,20 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.Queue;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An unbounded {@link TransferQueue} based on linked nodes.
@@ -63,15 +63,16 @@
  * asynchronous nature of these queues, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
- * <p>Bulk operations that add, remove, or examine multiple elements,
- * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
- * are <em>not</em> guaranteed to be performed atomically.
- * For example, a {@code forEach} traversal concurrent with an {@code
- * addAll} operation might observe only some of the added elements.
- *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
  *
  * <p>Memory consistency effects: As with other concurrent
  * collections, actions in a thread prior to placing an object into a
@@ -80,10 +81,6 @@
  * actions subsequent to the access or removal of that element from
  * the {@code LinkedTransferQueue} in another thread.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -96,8 +93,8 @@
      * *** Overview of Dual Queues with Slack ***
      *
      * Dual Queues, introduced by Scherer and Scott
-     * (http://www.cs.rochester.edu/~scott/papers/2004_DISC_dual_DS.pdf)
-     * are (linked) queues in which nodes may represent either data or
+     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
+     * (linked) queues in which nodes may represent either data or
      * requests.  When a thread tries to enqueue a data node, but
      * encounters a request node, it instead "matches" and removes it;
      * and vice versa for enqueuing requests. Blocking Dual Queues
@@ -159,8 +156,9 @@
      * correctly perform enqueue and dequeue operations by traversing
      * from a pointer to the initial node; CASing the item of the
      * first unmatched node on match and CASing the next field of the
-     * trailing node on appends.  While this would be a terrible idea
-     * in itself, it does have the benefit of not requiring ANY atomic
+     * trailing node on appends. (Plus some special-casing when
+     * initially empty).  While this would be a terrible idea in
+     * itself, it does have the benefit of not requiring ANY atomic
      * updates on head/tail fields.
      *
      * We introduce here an approach that lies between the extremes of
@@ -196,15 +194,15 @@
      * with a given probability per traversal step.
      *
      * In any strategy along these lines, because CASes updating
-     * fields may fail, the actual slack may exceed targeted slack.
-     * However, they may be retried at any time to maintain targets.
-     * Even when using very small slack values, this approach works
-     * well for dual queues because it allows all operations up to the
-     * point of matching or appending an item (hence potentially
-     * allowing progress by another thread) to be read-only, thus not
-     * introducing any further contention.  As described below, we
-     * implement this by performing slack maintenance retries only
-     * after these points.
+     * fields may fail, the actual slack may exceed targeted
+     * slack. However, they may be retried at any time to maintain
+     * targets.  Even when using very small slack values, this
+     * approach works well for dual queues because it allows all
+     * operations up to the point of matching or appending an item
+     * (hence potentially allowing progress by another thread) to be
+     * read-only, thus not introducing any further contention. As
+     * described below, we implement this by performing slack
+     * maintenance retries only after these points.
      *
      * As an accompaniment to such techniques, traversal overhead can
      * be further reduced without increasing contention of head
@@ -223,7 +221,7 @@
      * (Similar issues arise in non-GC environments.)  To cope with
      * this in our implementation, upon CASing to advance the head
      * pointer, we set the "next" link of the previous head to point
-     * only to itself; thus limiting the length of chains of dead nodes.
+     * only to itself; thus limiting the length of connected dead lists.
      * (We also take similar care to wipe out possibly garbage
      * retaining values held in other Node fields.)  However, doing so
      * adds some further complexity to traversal: If any "next"
@@ -266,6 +264,15 @@
      * interior nodes) except in the case of cancellation/removal (see
      * below).
      *
+     * We allow both the head and tail fields to be null before any
+     * nodes are enqueued; initializing upon first append.  This
+     * simplifies some other logic, as well as providing more
+     * efficient explicit control paths instead of letting JVMs insert
+     * implicit NullPointerExceptions when they are null.  While not
+     * currently fully implemented, we also leave open the possibility
+     * of re-nulling these fields when empty (which is complicated to
+     * arrange, for little benefit.)
+     *
      * All enqueue/dequeue operations are handled by the single method
      * "xfer" with parameters indicating whether to act as some form
      * of offer, put, poll, take, or transfer (each possibly with
@@ -273,40 +280,44 @@
      * method outweighs the code bulk and maintenance problems of
      * using separate methods for each case.
      *
-     * Operation consists of up to two phases. The first is implemented
-     * in method xfer, the second in method awaitMatch.
+     * Operation consists of up to three phases. The first is
+     * implemented within method xfer, the second in tryAppend, and
+     * the third in method awaitMatch.
      *
-     * 1. Traverse until matching or appending (method xfer)
+     * 1. Try to match an existing node
      *
-     *    Conceptually, we simply traverse all nodes starting from head.
-     *    If we encounter an unmatched node of opposite mode, we match
-     *    it and return, also updating head (by at least 2 hops) to
-     *    one past the matched node (or the node itself if it's the
-     *    pinned trailing node).  Traversals also check for the
-     *    possibility of falling off-list, in which case they restart.
+     *    Starting at head, skip already-matched nodes until finding
+     *    an unmatched node of opposite mode, if one exists, in which
+     *    case matching it and returning, also if necessary updating
+     *    head to one past the matched node (or the node itself if the
+     *    list has no other unmatched nodes). If the CAS misses, then
+     *    a loop retries advancing head by two steps until either
+     *    success or the slack is at most two. By requiring that each
+     *    attempt advances head by two (if applicable), we ensure that
+     *    the slack does not grow without bound. Traversals also check
+     *    if the initial head is now off-list, in which case they
+     *    start at the new head.
      *
-     *    If the trailing node of the list is reached, a match is not
-     *    possible.  If this call was untimed poll or tryTransfer
-     *    (argument "how" is NOW), return empty-handed immediately.
-     *    Else a new node is CAS-appended.  On successful append, if
-     *    this call was ASYNC (e.g. offer), an element was
-     *    successfully added to the end of the queue and we return.
+     *    If no candidates are found and the call was untimed
+     *    poll/offer, (argument "how" is NOW) return.
      *
-     *    Of course, this naive traversal is O(n) when no match is
-     *    possible.  We optimize the traversal by maintaining a tail
-     *    pointer, which is expected to be "near" the end of the list.
-     *    It is only safe to fast-forward to tail (in the presence of
-     *    arbitrary concurrent changes) if it is pointing to a node of
-     *    the same mode, even if it is dead (in this case no preceding
-     *    node could still be matchable by this traversal).  If we
-     *    need to restart due to falling off-list, we can again
-     *    fast-forward to tail, but only if it has changed since the
-     *    last traversal (else we might loop forever).  If tail cannot
-     *    be used, traversal starts at head (but in this case we
-     *    expect to be able to match near head).  As with head, we
-     *    CAS-advance the tail pointer by at least two hops.
+     * 2. Try to append a new node (method tryAppend)
      *
-     * 2. Await match or cancellation (method awaitMatch)
+     *    Starting at current tail pointer, find the actual last node
+     *    and try to append a new node (or if head was null, establish
+     *    the first node). Nodes can be appended only if their
+     *    predecessors are either already matched or are of the same
+     *    mode. If we detect otherwise, then a new node with opposite
+     *    mode must have been appended during traversal, so we must
+     *    restart at phase 1. The traversal and update steps are
+     *    otherwise similar to phase 1: Retrying upon CAS misses and
+     *    checking for staleness.  In particular, if a self-link is
+     *    encountered, then we can safely jump to a node on the list
+     *    by continuing the traversal at current head.
+     *
+     *    On successful append, if the call was ASYNC, return.
+     *
+     * 3. Await match or cancellation (method awaitMatch)
      *
      *    Wait for another thread to match node; instead cancelling if
      *    the current thread was interrupted or the wait timed out. On
@@ -360,12 +371,12 @@
      * from, the head of list.
      *
      * Without taking these into account, it would be possible for an
-     * unbounded number of supposedly removed nodes to remain reachable.
-     * Situations leading to such buildup are uncommon but can occur
-     * in practice; for example when a series of short timed calls to
-     * poll repeatedly time out at the trailing node but otherwise
-     * never fall off the list because of an untimed call to take() at
-     * the front of the queue.
+     * unbounded number of supposedly removed nodes to remain
+     * reachable.  Situations leading to such buildup are uncommon but
+     * can occur in practice; for example when a series of short timed
+     * calls to poll repeatedly time out but never otherwise fall off
+     * the list because of an untimed call to take at the front of the
+     * queue.
      *
      * When these cases arise, rather than always retraversing the
      * entire list to find an actual predecessor to unlink (which
@@ -378,9 +389,10 @@
      * We perform sweeps by the thread hitting threshold (rather than
      * background threads or by spreading work to other threads)
      * because in the main contexts in which removal occurs, the
-     * caller is timed-out or cancelled, which are not time-critical
-     * enough to warrant the overhead that alternatives would impose
-     * on other threads.
+     * caller is already timed-out, cancelled, or performing a
+     * potentially O(n) operation (e.g. remove(x)), none of which are
+     * time-critical enough to warrant the overhead that alternatives
+     * would impose on other threads.
      *
      * Because the sweepVotes estimate is conservative, and because
      * nodes become unlinked "naturally" as they fall off the head of
@@ -392,13 +404,6 @@
      * quiescent queues. The value defined below was chosen
      * empirically to balance these under various timeout scenarios.
      *
-     * Because traversal operations on the linked list of nodes are a
-     * natural opportunity to sweep dead nodes, we generally do so,
-     * including all the operations that might remove elements as they
-     * traverse, such as removeIf and Iterator.remove.  This largely
-     * eliminates long chains of dead interior nodes, except from
-     * cancelled or timed out blocking operations.
-     *
      * Note that we cannot self-link unlinked interior nodes during
      * sweeps. However, the associated garbage chains terminate when
      * some successor ultimately falls off the head of the list and is
@@ -439,72 +444,55 @@
 
     /**
      * Queue nodes. Uses Object, not E, for items to allow forgetting
-     * them after use.  Writes that are intrinsically ordered wrt
-     * other accesses or CASes use simple relaxed forms.
+     * them after use.  Relies heavily on Unsafe mechanics to minimize
+     * unnecessary ordering constraints: Writes that are intrinsically
+     * ordered wrt other accesses or CASes use simple relaxed forms.
      */
     static final class Node {
         final boolean isData;   // false if this is a request node
         volatile Object item;   // initially non-null if isData; CASed to match
         volatile Node next;
-        volatile Thread waiter; // null when not waiting for a match
+        volatile Thread waiter; // null until waiting
 
-        /**
-         * Constructs a data node holding item if item is non-null,
-         * else a request node.  Uses relaxed write because item can
-         * only be seen after piggy-backing publication via CAS.
-         */
-        Node(Object item) {
-            ITEM.set(this, item);
-            isData = (item != null);
-        }
-
-        /** Constructs a (matched data) dummy node. */
-        Node() {
-            isData = true;
-        }
-
+        // CAS methods for fields
         final boolean casNext(Node cmp, Node val) {
-            // assert val != null;
-            return NEXT.compareAndSet(this, cmp, val);
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
         }
 
         final boolean casItem(Object cmp, Object val) {
-            // assert isData == (cmp != null);
-            // assert isData == (val == null);
-            // assert !(cmp instanceof Node);
-            return ITEM.compareAndSet(this, cmp, val);
+            // assert cmp == null || cmp.getClass() != Node.class;
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext.
+         */
+        Node(Object item, boolean isData) {
+            U.putObject(this, ITEM, item); // relaxed write
+            this.isData = isData;
         }
 
         /**
          * Links node to itself to avoid garbage retention.  Called
          * only after CASing head field, so uses relaxed write.
          */
-        final void selfLink() {
-            // assert isMatched();
-            NEXT.setRelease(this, this);
-        }
-
-        final void appendRelaxed(Node next) {
-            // assert next != null;
-            // assert this.next == null;
-            NEXT.set(this, next);
+        final void forgetNext() {
+            U.putObject(this, NEXT, this);
         }
 
         /**
-         * Sets item (of a request node) to self and waiter to null,
-         * to avoid garbage retention after matching or cancelling.
-         * Uses relaxed writes because order is already constrained in
-         * the only calling contexts: item is forgotten only after
-         * volatile/atomic mechanics that extract items, and visitors
-         * of request nodes only ever check whether item is null.
-         * Similarly, clearing waiter follows either CAS or return
-         * from park (if ever parked; else we don't care).
+         * Sets item to self and waiter to null, to avoid garbage
+         * retention after matching or cancelling. Uses relaxed writes
+         * because order is already constrained in the only calling
+         * contexts: item is forgotten only after volatile/atomic
+         * mechanics that extract items.  Similarly, clearing waiter
+         * follows either CAS or return from park (if ever parked;
+         * else we don't care).
          */
         final void forgetContents() {
-            // assert isMatched();
-            if (!isData)
-                ITEM.set(this, this);
-            WAITER.set(this, null);
+            U.putObject(this, ITEM, this);
+            U.putObject(this, WAITER, null);
         }
 
         /**
@@ -512,16 +500,15 @@
          * case of artificial matches due to cancellation.
          */
         final boolean isMatched() {
-            return isData == (item == null);
+            Object x = item;
+            return (x == this) || ((x == null) == isData);
         }
 
-        /** Tries to CAS-match this node; if successful, wakes waiter. */
-        final boolean tryMatch(Object cmp, Object val) {
-            if (casItem(cmp, val)) {
-                LockSupport.unpark(waiter);
-                return true;
-            }
-            return false;
+        /**
+         * Returns true if this is an unmatched request node.
+         */
+        final boolean isUnmatchedRequest() {
+            return !isData && item == null;
         }
 
         /**
@@ -531,118 +518,69 @@
          */
         final boolean cannotPrecede(boolean haveData) {
             boolean d = isData;
-            return d != haveData && d != (item == null);
+            Object x;
+            return d != haveData && (x = item) != this && (x != null) == d;
+        }
+
+        /**
+         * Tries to artificially match a data node -- used by remove.
+         */
+        final boolean tryMatchData() {
+            // assert isData;
+            Object x = item;
+            if (x != null && x != this && casItem(x, null)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
         }
 
         private static final long serialVersionUID = -3375979862319811754L;
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long ITEM;
+        private static final long NEXT;
+        private static final long WAITER;
+        static {
+            try {
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+                WAITER = U.objectFieldOffset
+                    (Node.class.getDeclaredField("waiter"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
     }
 
-    /**
-     * A node from which the first live (non-matched) node (if any)
-     * can be reached in O(1) time.
-     * Invariants:
-     * - all live nodes are reachable from head via .next
-     * - head != null
-     * - (tmp = head).next != tmp || tmp != head
-     * Non-invariants:
-     * - head may or may not be live
-     * - it is permitted for tail to lag behind head, that is, for tail
-     *   to not be reachable from head!
-     */
+    /** head of the queue; null until first enqueue */
     transient volatile Node head;
 
-    /**
-     * A node from which the last node on list (that is, the unique
-     * node with node.next == null) can be reached in O(1) time.
-     * Invariants:
-     * - the last node is always reachable from tail via .next
-     * - tail != null
-     * Non-invariants:
-     * - tail may or may not be live
-     * - it is permitted for tail to lag behind head, that is, for tail
-     *   to not be reachable from head!
-     * - tail.next may or may not be self-linked.
-     */
+    /** tail of the queue; null until first append */
     private transient volatile Node tail;
 
-    /** The number of apparent failures to unsplice cancelled nodes */
+    /** The number of apparent failures to unsplice removed nodes */
     private transient volatile int sweepVotes;
 
+    // CAS methods for fields
     private boolean casTail(Node cmp, Node val) {
-        // assert cmp != null;
-        // assert val != null;
-        return TAIL.compareAndSet(this, cmp, val);
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
     }
 
     private boolean casHead(Node cmp, Node val) {
-        return HEAD.compareAndSet(this, cmp, val);
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
     }
 
-    /** Atomic version of ++sweepVotes. */
-    private int incSweepVotes() {
-        return (int) SWEEPVOTES.getAndAdd(this, 1) + 1;
+    private boolean casSweepVotes(int cmp, int val) {
+        return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
     }
 
-    /**
-     * Tries to CAS pred.next (or head, if pred is null) from c to p.
-     * Caller must ensure that we're not unlinking the trailing node.
+    /*
+     * Possible values for "how" argument in xfer method.
      */
-    private boolean tryCasSuccessor(Node pred, Node c, Node p) {
-        // assert p != null;
-        // assert c.isData != (c.item != null);
-        // assert c != p;
-        if (pred != null)
-            return pred.casNext(c, p);
-        if (casHead(c, p)) {
-            c.selfLink();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Collapses dead (matched) nodes between pred and q.
-     * @param pred the last known live node, or null if none
-     * @param c the first dead node
-     * @param p the last dead node
-     * @param q p.next: the next live node, or null if at end
-     * @return pred if pred still alive and CAS succeeded; else p
-     */
-    private Node skipDeadNodes(Node pred, Node c, Node p, Node q) {
-        // assert pred != c;
-        // assert p != q;
-        // assert c.isMatched();
-        // assert p.isMatched();
-        if (q == null) {
-            // Never unlink trailing node.
-            if (c == p) return pred;
-            q = p;
-        }
-        return (tryCasSuccessor(pred, c, q)
-                && (pred == null || !pred.isMatched()))
-            ? pred : p;
-    }
-
-    /**
-     * Collapses dead (matched) nodes from h (which was once head) to p.
-     * Caller ensures all nodes from h up to and including p are dead.
-     */
-    private void skipDeadNodesNearHead(Node h, Node p) {
-        // assert h != null;
-        // assert h != p;
-        // assert p.isMatched();
-        for (;;) {
-            final Node q;
-            if ((q = p.next) == null) break;
-            else if (!q.isMatched()) { p = q; break; }
-            else if (p == (p = q)) return;
-        }
-        if (casHead(h, p))
-            h.selfLink();
-    }
-
-    /* Possible values for "how" argument in xfer method. */
-
     private static final int NOW   = 0; // for untimed poll, tryTransfer
     private static final int ASYNC = 1; // for offer, put, add
     private static final int SYNC  = 2; // for transfer, take
@@ -658,32 +596,84 @@
      * @return an item if matched, else e
      * @throws NullPointerException if haveData mode but e is null
      */
-    @SuppressWarnings("unchecked")
     private E xfer(E e, boolean haveData, int how, long nanos) {
         if (haveData && (e == null))
             throw new NullPointerException();
+        Node s = null;                        // the node to append, if needed
 
-        restart: for (Node s = null, t = null, h = null;;) {
-            for (Node p = (t != (t = tail) && t.isData == haveData) ? t
-                     : (h = head);; ) {
-                final Node q; final Object item;
-                if (p.isData != haveData
-                    && haveData == ((item = p.item) == null)) {
-                    if (h == null) h = head;
-                    if (p.tryMatch(item, e)) {
-                        if (h != p) skipDeadNodesNearHead(h, p);
-                        return (E) item;
+        retry:
+        for (;;) {                            // restart on append race
+
+            for (Node h = head, p = h; p != null;) { // find & match first node
+                boolean isData = p.isData;
+                Object item = p.item;
+                if (item != p && (item != null) == isData) { // unmatched
+                    if (isData == haveData)   // can't match
+                        break;
+                    if (p.casItem(item, e)) { // match
+                        for (Node q = p; q != h;) {
+                            Node n = q.next;  // update by 2 unless singleton
+                            if (head == h && casHead(h, n == null ? q : n)) {
+                                h.forgetNext();
+                                break;
+                            }                 // advance and retry
+                            if ((h = head)   == null ||
+                                (q = h.next) == null || !q.isMatched())
+                                break;        // unless slack < 2
+                        }
+                        LockSupport.unpark(p.waiter);
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        return itemE;
                     }
                 }
-                if ((q = p.next) == null) {
-                    if (how == NOW) return e;
-                    if (s == null) s = new Node(e);
-                    if (!p.casNext(null, s)) continue;
-                    if (p != t) casTail(t, s);
-                    if (how == ASYNC) return e;
-                    return awaitMatch(s, p, e, (how == TIMED), nanos);
+                Node n = p.next;
+                p = (p != n) ? n : (h = head); // Use head if p offlist
+            }
+
+            if (how != NOW) {                 // No matches available
+                if (s == null)
+                    s = new Node(e, haveData);
+                Node pred = tryAppend(s, haveData);
+                if (pred == null)
+                    continue retry;           // lost race vs opposite mode
+                if (how != ASYNC)
+                    return awaitMatch(s, pred, e, (how == TIMED), nanos);
+            }
+            return e; // not waiting
+        }
+    }
+
+    /**
+     * Tries to append node s as tail.
+     *
+     * @param s the node to append
+     * @param haveData true if appending in data mode
+     * @return null on failure due to losing race with append in
+     * different mode, else s's predecessor, or s itself if no
+     * predecessor
+     */
+    private Node tryAppend(Node s, boolean haveData) {
+        for (Node t = tail, p = t;;) {        // move p to last node and append
+            Node n, u;                        // temps for reads of next & tail
+            if (p == null && (p = head) == null) {
+                if (casHead(null, s))
+                    return s;                 // initialize
+            }
+            else if (p.cannotPrecede(haveData))
+                return null;                  // lost race vs opposite mode
+            else if ((n = p.next) != null)    // not last; keep traversing
+                p = p != t && t != (u = tail) ? (t = u) : // stale tail
+                    (p != n) ? n : null;      // restart if off list
+            else if (!p.casNext(null, s))
+                p = p.next;                   // re-read on CAS failure
+            else {
+                if (p != t) {                 // update if slack now >= 2
+                    while ((tail != t || !casTail(t, s)) &&
+                           (t = tail)   != null &&
+                           (s = t.next) != null && // advance and retry
+                           (s = s.next) != null && s != t);
                 }
-                if (p == (p = q)) continue restart;
+                return p;
             }
         }
     }
@@ -692,9 +682,9 @@
      * Spins/yields/blocks until node s is matched or caller gives up.
      *
      * @param s the waiting node
-     * @param pred the predecessor of s, or null if unknown (the null
-     * case does not occur in any current calls but may in possible
-     * future extensions)
+     * @param pred the predecessor of s, or s itself if it has no
+     * predecessor, or null if unknown (the null case does not occur
+     * in any current calls but may in possible future extensions)
      * @param e the comparison value for checking match
      * @param timed if true, wait only until timeout elapses
      * @param nanos timeout in nanosecs, used only if timed is true
@@ -707,20 +697,17 @@
         ThreadLocalRandom randomYields = null; // bound if needed
 
         for (;;) {
-            final Object item;
-            if ((item = s.item) != e) {       // matched
+            Object item = s.item;
+            if (item != e) {                  // matched
                 // assert item != s;
                 s.forgetContents();           // avoid garbage
                 @SuppressWarnings("unchecked") E itemE = (E) item;
                 return itemE;
             }
             else if (w.isInterrupted() || (timed && nanos <= 0L)) {
-                // try to cancel and unlink
-                if (s.casItem(e, s.isData ? null : s)) {
-                    unsplice(pred, s);
+                unsplice(pred, s);           // try to unlink and cancel
+                if (s.casItem(e, s))         // return normally if lost CAS
                     return e;
-                }
-                // return normally if lost CAS
             }
             else if (spins < 0) {            // establish spins at/near front
                 if ((spins = spinsFor(pred, s.isData)) > 0)
@@ -764,32 +751,34 @@
     /* -------------- Traversal methods -------------- */
 
     /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node succ(Node p) {
+        Node next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
      * Returns the first unmatched data node, or null if none.
-     * Callers must recheck if the returned node is unmatched
-     * before using.
+     * Callers must recheck if the returned node's item field is null
+     * or self-linked before using.
      */
     final Node firstDataNode() {
-        Node first = null;
         restartFromHead: for (;;) {
-            Node h = head, p = h;
-            while (p != null) {
-                if (p.item != null) {
-                    if (p.isData) {
-                        first = p;
-                        break;
-                    }
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p)
+                        return p;
                 }
-                else if (!p.isData)
+                else if (item == null)
                     break;
-                final Node q;
-                if ((q = p.next) == null)
-                    break;
-                if (p == (p = q))
+                if (p == (p = p.next))
                     continue restartFromHead;
             }
-            if (p != h && casHead(h, p))
-                h.selfLink();
-            return first;
+            return null;
         }
     }
 
@@ -822,7 +811,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null) {
+                    if (item != null && item != p) {
                         if (a == null)
                             a = new String[4];
                         else if (size == a.length)
@@ -851,7 +840,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null) {
+                    if (item != null && item != p) {
                         if (x == null)
                             x = new Object[4];
                         else if (size == x.length)
@@ -930,50 +919,76 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        Objects.requireNonNull(a);
+        if (a == null) throw new NullPointerException();
         return (T[]) toArrayInternal(a);
     }
 
-    /**
-     * Weakly-consistent iterator.
-     *
-     * Lazily updated ancestor is expected to be amortized O(1) remove(),
-     * but O(n) in the worst case, when lastRet is concurrently deleted.
-     */
     final class Itr implements Iterator<E> {
         private Node nextNode;   // next node to return item for
         private E nextItem;      // the corresponding item
         private Node lastRet;    // last returned node, to support remove
-        private Node ancestor;   // Helps unlink lastRet on remove()
+        private Node lastPred;   // predecessor to unlink lastRet
 
         /**
-         * Moves to next node after pred, or first node if pred null.
+         * Moves to next node after prev, or first node if prev null.
          */
-        @SuppressWarnings("unchecked")
-        private void advance(Node pred) {
-            for (Node p = (pred == null) ? head : pred.next, c = p;
-                 p != null; ) {
-                final Object item;
-                if ((item = p.item) != null && p.isData) {
-                    nextNode = p;
-                    nextItem = (E) item;
-                    if (c != p)
-                        tryCasSuccessor(pred, c, p);
-                    return;
-                }
-                else if (!p.isData && item == null)
-                    break;
-                if (c != p && !tryCasSuccessor(pred, c, c = p)) {
-                    pred = p;
-                    c = p = p.next;
-                }
-                else if (p == (p = p.next)) {
-                    pred = null;
-                    c = p = head;
-                }
+        private void advance(Node prev) {
+            /*
+             * To track and avoid buildup of deleted nodes in the face
+             * of calls to both Queue.remove and Itr.remove, we must
+             * include variants of unsplice and sweep upon each
+             * advance: Upon Itr.remove, we may need to catch up links
+             * from lastPred, and upon other removes, we might need to
+             * skip ahead from stale nodes and unsplice deleted ones
+             * found while advancing.
+             */
+
+            Node r, b; // reset lastPred upon possible deletion of lastRet
+            if ((r = lastRet) != null && !r.isMatched())
+                lastPred = r;    // next lastPred is old lastRet
+            else if ((b = lastPred) == null || b.isMatched())
+                lastPred = null; // at start of list
+            else {
+                Node s, n;       // help with removal of lastPred.next
+                while ((s = b.next) != null &&
+                       s != b && s.isMatched() &&
+                       (n = s.next) != null && n != s)
+                    b.casNext(s, n);
             }
-            nextItem = null;
+
+            this.lastRet = prev;
+
+            for (Node p = prev, s, n;;) {
+                s = (p == null) ? head : p.next;
+                if (s == null)
+                    break;
+                else if (s == p) {
+                    p = null;
+                    continue;
+                }
+                Object item = s.item;
+                if (s.isData) {
+                    if (item != null && item != s) {
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        nextItem = itemE;
+                        nextNode = s;
+                        return;
+                    }
+                }
+                else if (item == null)
+                    break;
+                // assert s.isMatched();
+                if (p == null)
+                    p = s;
+                else if ((n = s.next) == null)
+                    break;
+                else if (s == n)
+                    p = null;
+                else
+                    p.casNext(s, n);
+            }
             nextNode = null;
+            nextItem = null;
         }
 
         Itr() {
@@ -985,67 +1000,25 @@
         }
 
         public final E next() {
-            final Node p;
-            if ((p = nextNode) == null) throw new NoSuchElementException();
+            Node p = nextNode;
+            if (p == null) throw new NoSuchElementException();
             E e = nextItem;
-            advance(lastRet = p);
+            advance(p);
             return e;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            Node q = null;
-            for (Node p; (p = nextNode) != null; advance(q = p))
-                action.accept(nextItem);
-            if (q != null)
-                lastRet = q;
-        }
-
         public final void remove() {
             final Node lastRet = this.lastRet;
             if (lastRet == null)
                 throw new IllegalStateException();
             this.lastRet = null;
-            if (lastRet.item == null)   // already deleted?
-                return;
-            // Advance ancestor, collapsing intervening dead nodes
-            Node pred = ancestor;
-            for (Node p = (pred == null) ? head : pred.next, c = p, q;
-                 p != null; ) {
-                if (p == lastRet) {
-                    final Object item;
-                    if ((item = p.item) != null)
-                        p.tryMatch(item, null);
-                    if ((q = p.next) == null) q = p;
-                    if (c != q) tryCasSuccessor(pred, c, q);
-                    ancestor = pred;
-                    return;
-                }
-                final Object item; final boolean pAlive;
-                if (pAlive = ((item = p.item) != null && p.isData)) {
-                    // exceptionally, nothing to do
-                }
-                else if (!p.isData && item == null)
-                    break;
-                if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) {
-                    pred = p;
-                    c = p = p.next;
-                }
-                else if (p == (p = p.next)) {
-                    pred = null;
-                    c = p = head;
-                }
-            }
-            // traversal failed to find lastRet; must have been deleted;
-            // leave ancestor at original location to avoid overshoot;
-            // better luck next time!
-
-            // assert lastRet.isMatched();
+            if (lastRet.tryMatchData())
+                unsplice(lastPred, lastRet);
         }
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    final class LTQSpliterator implements Spliterator<E> {
+    final class LTQSpliterator<E> implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
         Node current;       // current node; null until initialized
         int batch;          // batch size for splits
@@ -1053,90 +1026,79 @@
         LTQSpliterator() {}
 
         public Spliterator<E> trySplit() {
-            Node p, q;
-            if ((p = current()) == null || (q = p.next) == null)
-                return null;
-            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
-            Object[] a = null;
-            do {
-                final Object item = p.item;
-                if (p.isData) {
-                    if (item != null) {
-                        if (a == null)
-                            a = new Object[n];
-                        a[i++] = item;
-                    }
-                } else if (item == null) {
-                    p = null;
-                    break;
+            Node p;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    Object e = p.item;
+                    if (e != p && (a[i] = e) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && i < n && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
                 }
-                if (p == (p = q))
-                    p = firstDataNode();
-            } while (p != null && (q = p.next) != null && i < n);
-            setCurrent(p);
-            return (i == 0) ? null :
-                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
-                                                   Spliterator.NONNULL |
-                                                   Spliterator.CONCURRENT));
+            }
+            return null;
         }
 
+        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            final Node p;
-            if ((p = current()) != null) {
-                current = null;
+            Node p;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
                 exhausted = true;
-                forEachFrom(action, p);
+                do {
+                    Object e = p.item;
+                    if (e != null && e != p)
+                        action.accept((E)e);
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && p.isData);
             }
         }
 
         @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
             Node p;
-            if ((p = current()) != null) {
-                E e = null;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
+                Object e;
                 do {
-                    final Object item = p.item;
-                    final boolean isData = p.isData;
+                    if ((e = p.item) == p)
+                        e = null;
                     if (p == (p = p.next))
-                        p = head;
-                    if (isData) {
-                        if (item != null) {
-                            e = (E) item;
-                            break;
-                        }
-                    }
-                    else if (item == null)
-                        p = null;
-                } while (p != null);
-                setCurrent(p);
+                        p = firstDataNode();
+                } while (e == null && p != null && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
                 if (e != null) {
-                    action.accept(e);
+                    action.accept((E)e);
                     return true;
                 }
             }
             return false;
         }
 
-        private void setCurrent(Node p) {
-            if ((current = p) == null)
-                exhausted = true;
-        }
-
-        private Node current() {
-            Node p;
-            if ((p = current) == null && !exhausted)
-                setCurrent(p = firstDataNode());
-            return p;
-        }
-
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return (Spliterator.ORDERED |
-                    Spliterator.NONNULL |
-                    Spliterator.CONCURRENT);
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
         }
     }
 
@@ -1157,7 +1119,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LTQSpliterator();
+        return new LTQSpliterator<E>();
     }
 
     /* -------------- Removal methods -------------- */
@@ -1167,15 +1129,10 @@
      * the given predecessor.
      *
      * @param pred a node that was at one time known to be the
-     * predecessor of s
+     * predecessor of s, or null or s itself if s is/was at head
      * @param s the node to be unspliced
      */
     final void unsplice(Node pred, Node s) {
-        // assert pred != null;
-        // assert pred != s;
-        // assert s != null;
-        // assert s.isMatched();
-        // assert (SWEEP_THRESHOLD & (SWEEP_THRESHOLD - 1)) == 0;
         s.waiter = null; // disable signals
         /*
          * See above for rationale. Briefly: if pred still points to
@@ -1184,13 +1141,13 @@
          * nor s are head or offlist, add to sweepVotes, and if enough
          * votes have accumulated, sweep.
          */
-        if (pred != null && pred.next == s) {
+        if (pred != null && pred != s && pred.next == s) {
             Node n = s.next;
             if (n == null ||
                 (n != s && pred.casNext(s, n) && pred.isMatched())) {
                 for (;;) {               // check if at, or could be, head
                     Node h = head;
-                    if (h == pred || h == s)
+                    if (h == pred || h == s || h == null)
                         return;          // at head or list empty
                     if (!h.isMatched())
                         break;
@@ -1198,12 +1155,21 @@
                     if (hn == null)
                         return;          // now empty
                     if (hn != h && casHead(h, hn))
-                        h.selfLink();  // advance head
+                        h.forgetNext();  // advance head
                 }
-                // sweep every SWEEP_THRESHOLD votes
-                if (pred.next != pred && s.next != s // recheck if offlist
-                    && (incSweepVotes() & (SWEEP_THRESHOLD - 1)) == 0)
-                    sweep();
+                if (pred.next != pred && s.next != s) { // recheck if offlist
+                    for (;;) {           // sweep now if enough votes
+                        int v = sweepVotes;
+                        if (v < SWEEP_THRESHOLD) {
+                            if (casSweepVotes(v, v + 1))
+                                break;
+                        }
+                        else if (casSweepVotes(v, 0)) {
+                            sweep();
+                            break;
+                        }
+                    }
+                }
             }
         }
     }
@@ -1228,10 +1194,35 @@
     }
 
     /**
+     * Main implementation of remove(Object)
+     */
+    private boolean findAndRemove(Object e) {
+        if (e != null) {
+            for (Node pred = null, p = head; p != null; ) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && e.equals(item) &&
+                        p.tryMatchData()) {
+                        unsplice(pred, p);
+                        return true;
+                    }
+                }
+                else if (item == null)
+                    break;
+                pred = p;
+                if ((p = p.next) == pred) { // stale
+                    pred = null;
+                    p = head;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Creates an initially empty {@code LinkedTransferQueue}.
      */
     public LinkedTransferQueue() {
-        head = tail = new Node();
     }
 
     /**
@@ -1244,18 +1235,8 @@
      *         of its elements are null
      */
     public LinkedTransferQueue(Collection<? extends E> c) {
-        Node h = null, t = null;
-        for (E e : c) {
-            Node newNode = new Node(Objects.requireNonNull(e));
-            if (h == null)
-                h = t = newNode;
-            else
-                t.appendRelaxed(t = newNode);
-        }
-        if (h == null)
-            h = t = new Node();
-        head = h;
-        tail = t;
+        this();
+        addAll(c);
     }
 
     /**
@@ -1274,7 +1255,8 @@
      * return {@code false}.
      *
      * @return {@code true} (as specified by
-     *  {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
+     *  {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
+     *  BlockingQueue.offer})
      * @throws NullPointerException if the specified element is null
      */
     public boolean offer(E e, long timeout, TimeUnit unit) {
@@ -1386,12 +1368,15 @@
      * @throws IllegalArgumentException {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; (e = poll()) != null; n++)
+        for (E e; (e = poll()) != null;) {
             c.add(e);
+            ++n;
+        }
         return n;
     }
 
@@ -1400,12 +1385,15 @@
      * @throws IllegalArgumentException {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; n < maxElements && (e = poll()) != null; n++)
+        for (E e; n < maxElements && (e = poll()) != null;) {
             c.add(e);
+            ++n;
+        }
         return n;
     }
 
@@ -1427,7 +1415,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null) {
+                    if (item != null && item != p) {
                         @SuppressWarnings("unchecked") E e = (E) item;
                         return e;
                     }
@@ -1455,7 +1443,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null)
+                    if (item != null && item != p)
                         break;
                 }
                 else if (item == null)
@@ -1499,31 +1487,7 @@
      * @return {@code true} if this queue changed as a result of the call
      */
     public boolean remove(Object o) {
-        if (o == null) return false;
-        restartFromHead: for (;;) {
-            for (Node p = head, pred = null; p != null; ) {
-                Node q = p.next;
-                final Object item;
-                if ((item = p.item) != null) {
-                    if (p.isData) {
-                        if (o.equals(item) && p.tryMatch(item, null)) {
-                            skipDeadNodes(pred, p, p, q);
-                            return true;
-                        }
-                        pred = p; p = q; continue;
-                    }
-                }
-                else if (!p.isData)
-                    break;
-                for (Node c = p;; q = p.next) {
-                    if (q == null || !q.isMatched()) {
-                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                    }
-                    if (p == (p = q)) continue restartFromHead;
-                }
-            }
-            return false;
-        }
+        return findAndRemove(o);
     }
 
     /**
@@ -1535,29 +1499,18 @@
      * @return {@code true} if this queue contains the specified element
      */
     public boolean contains(Object o) {
-        if (o == null) return false;
-        restartFromHead: for (;;) {
-            for (Node p = head, pred = null; p != null; ) {
-                Node q = p.next;
-                final Object item;
-                if ((item = p.item) != null) {
-                    if (p.isData) {
-                        if (o.equals(item))
-                            return true;
-                        pred = p; p = q; continue;
-                    }
+        if (o != null) {
+            for (Node p = head; p != null; p = succ(p)) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && o.equals(item))
+                        return true;
                 }
-                else if (!p.isData)
+                else if (item == null)
                     break;
-                for (Node c = p;; q = p.next) {
-                    if (q == null || !q.isMatched()) {
-                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                    }
-                    if (p == (p = q)) continue restartFromHead;
-                }
             }
-            return false;
         }
+        return false;
     }
 
     /**
@@ -1565,7 +1518,8 @@
      * {@code LinkedTransferQueue} is not capacity constrained.
      *
      * @return {@code Integer.MAX_VALUE} (as specified by
-     *         {@link BlockingQueue#remainingCapacity()})
+     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
+     *         BlockingQueue.remainingCapacity})
      */
     public int remainingCapacity() {
         return Integer.MAX_VALUE;
@@ -1597,149 +1551,33 @@
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
-
-        // Read in elements until trailing null sentinel found
-        Node h = null, t = null;
-        for (Object item; (item = s.readObject()) != null; ) {
-            Node newNode = new Node(item);
-            if (h == null)
-                h = t = newNode;
-            else
-                t.appendRelaxed(t = newNode);
-        }
-        if (h == null)
-            h = t = new Node();
-        head = h;
-        tail = t;
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
-
-    public void clear() {
-        bulkRemove(e -> true);
-    }
-
-    /**
-     * Tolerate this many consecutive dead nodes before CAS-collapsing.
-     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
-     */
-    private static final int MAX_HOPS = 8;
-
-    /** Implementation of bulk remove methods. */
-    @SuppressWarnings("unchecked")
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        boolean removed = false;
-        restartFromHead: for (;;) {
-            int hops = MAX_HOPS;
-            // c will be CASed to collapse intervening dead nodes between
-            // pred (or head if null) and p.
-            for (Node p = head, c = p, pred = null, q; p != null; p = q) {
-                q = p.next;
-                final Object item; boolean pAlive;
-                if (pAlive = ((item = p.item) != null && p.isData)) {
-                    if (filter.test((E) item)) {
-                        if (p.tryMatch(item, null))
-                            removed = true;
-                        pAlive = false;
-                    }
-                }
-                else if (!p.isData && item == null)
-                    break;
-                if (pAlive || q == null || --hops == 0) {
-                    // p might already be self-linked here, but if so:
-                    // - CASing head will surely fail
-                    // - CASing pred's next will be useless but harmless.
-                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
-                        || pAlive) {
-                        // if CAS failed or alive, abandon old pred
-                        hops = MAX_HOPS;
-                        pred = p;
-                        c = q;
-                    }
-                } else if (p == q)
-                    continue restartFromHead;
-            }
-            return removed;
-        }
-    }
-
-    /**
-     * Runs action on each element found during a traversal starting at p.
-     * If p is null, the action is not run.
-     */
-    @SuppressWarnings("unchecked")
-    void forEachFrom(Consumer<? super E> action, Node p) {
-        for (Node pred = null; p != null; ) {
-            Node q = p.next;
-            final Object item;
-            if ((item = p.item) != null) {
-                if (p.isData) {
-                    action.accept((E) item);
-                    pred = p; p = q; continue;
-                }
-            }
-            else if (!p.isData)
+        s.defaultReadObject();
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E) s.readObject();
+            if (item == null)
                 break;
-            for (Node c = p;; q = p.next) {
-                if (q == null || !q.isMatched()) {
-                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
-                }
-                if (p == (p = q)) { pred = null; p = head; break; }
-            }
+            else
+                offer(item);
         }
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        forEachFrom(action, head);
-    }
+    // Unsafe mechanics
 
-    // VarHandle mechanics
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
-    private static final VarHandle SWEEPVOTES;
-    static final VarHandle ITEM;
-    static final VarHandle NEXT;
-    static final VarHandle WAITER;
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long SWEEPVOTES;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
-                                   Node.class);
-            TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
-                                   Node.class);
-            SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
-                                         int.class);
-            ITEM = l.findVarHandle(Node.class, "item", Object.class);
-            NEXT = l.findVarHandle(Node.class, "next", Node.class);
-            WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
+            HEAD = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("tail"));
+            SWEEPVOTES = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/Phaser.java b/ojluni/src/main/java/java/util/concurrent/Phaser.java
index d878e45..9ef9936 100644
--- a/ojluni/src/main/java/java/util/concurrent/Phaser.java
+++ b/ojluni/src/main/java/java/util/concurrent/Phaser.java
@@ -35,15 +35,14 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.LockSupport;
 
 /**
  * A reusable synchronization barrier, similar in functionality to
- * {@link CyclicBarrier} and {@link CountDownLatch} but supporting
- * more flexible usage.
+ * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * but supporting more flexible usage.
  *
  * <p><b>Registration.</b> Unlike the case for other barriers, the
  * number of parties <em>registered</em> to synchronize on a phaser
@@ -153,46 +152,49 @@
  * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
  * to control a one-shot action serving a variable number of parties.
  * The typical idiom is for the method setting this up to first
- * register, then start all the actions, then deregister, as in:
+ * register, then start the actions, then deregister, as in:
  *
  * <pre> {@code
  * void runTasks(List<Runnable> tasks) {
- *   Phaser startingGate = new Phaser(1); // "1" to register self
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
  *   // create and start threads
- *   for (Runnable task : tasks) {
- *     startingGate.register();
- *     new Thread(() -> {
- *       startingGate.arriveAndAwaitAdvance();
- *       task.run();
- *     }).start();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
  *   }
  *
- *   // deregister self to allow threads to proceed
- *   startingGate.arriveAndDeregister();
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
  * }}</pre>
  *
  * <p>One way to cause a set of threads to repeatedly perform actions
  * for a given number of iterations is to override {@code onAdvance}:
  *
  * <pre> {@code
- * void startTasks(List<Runnable> tasks, int iterations) {
- *   Phaser phaser = new Phaser() {
+ * void startTasks(List<Runnable> tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
  *     protected boolean onAdvance(int phase, int registeredParties) {
- *       return phase >= iterations - 1 || registeredParties == 0;
+ *       return phase >= iterations || registeredParties == 0;
  *     }
  *   };
  *   phaser.register();
- *   for (Runnable task : tasks) {
+ *   for (final Runnable task : tasks) {
  *     phaser.register();
- *     new Thread(() -> {
- *       do {
- *         task.run();
- *         phaser.arriveAndAwaitAdvance();
- *       } while (!phaser.isTerminated());
- *     }).start();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
  *   }
- *   // allow threads to proceed; don't wait for them
- *   phaser.arriveAndDeregister();
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
  * }}</pre>
  *
  * If the main task must later await termination, it
@@ -219,6 +221,7 @@
  *   phaser.arriveAndDeregister();
  * }}</pre>
  *
+ *
  * <p>To create a set of {@code n} tasks using a tree of phasers, you
  * could use code of the following form, assuming a Task class with a
  * constructor accepting a {@code Phaser} that it registers with upon
@@ -345,6 +348,10 @@
     private final AtomicReference<QNode> evenQ;
     private final AtomicReference<QNode> oddQ;
 
+    private AtomicReference<QNode> queueFor(int phase) {
+        return ((phase & 1) == 0) ? evenQ : oddQ;
+    }
+
     /**
      * Returns message string for bounds exceptions on arrival.
      */
@@ -381,7 +388,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (STATE.compareAndSet(this, s, s-=adjust)) {
+            if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
                 if (unarrived == 1) {
                     long n = s & PARTIES_MASK;  // base of next state
                     int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -394,12 +401,12 @@
                             n |= nextUnarrived;
                         int nextPhase = (phase + 1) & MAX_PHASE;
                         n |= (long)nextPhase << PHASE_SHIFT;
-                        STATE.compareAndSet(this, s, n);
+                        U.compareAndSwapLong(this, STATE, s, n);
                         releaseWaiters(phase);
                     }
                     else if (nextUnarrived == 0) { // propagate deregistration
                         phase = parent.doArrive(ONE_DEREGISTER);
-                        STATE.compareAndSet(this, s, s | EMPTY);
+                        U.compareAndSwapLong(this, STATE, s, s | EMPTY);
                     }
                     else
                         phase = parent.doArrive(ONE_ARRIVAL);
@@ -434,13 +441,13 @@
                 if (parent == null || reconcileState() == s) {
                     if (unarrived == 0)             // wait out advance
                         root.internalAwaitAdvance(phase, null);
-                    else if (STATE.compareAndSet(this, s, s + adjust))
+                    else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
                         break;
                 }
             }
             else if (parent == null) {              // 1st root registration
                 long next = ((long)phase << PHASE_SHIFT) | adjust;
-                if (STATE.compareAndSet(this, s, next))
+                if (U.compareAndSwapLong(this, STATE, s, next))
                     break;
             }
             else {
@@ -452,8 +459,8 @@
                         // finish registration whenever parent registration
                         // succeeded, even when racing with termination,
                         // since these are part of the same "transaction".
-                        while (!STATE.weakCompareAndSet
-                               (this, s,
+                        while (!U.compareAndSwapLong
+                               (this, STATE, s,
                                 ((long)phase << PHASE_SHIFT) | adjust)) {
                             s = state;
                             phase = (int)(root.state >>> PHASE_SHIFT);
@@ -484,8 +491,8 @@
             // CAS to root phase with current parties, tripping unarrived
             while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
                    (int)(s >>> PHASE_SHIFT) &&
-                   !STATE.weakCompareAndSet
-                   (this, s,
+                   !U.compareAndSwapLong
+                   (this, STATE, s,
                     s = (((long)phase << PHASE_SHIFT) |
                          ((phase < 0) ? (s & COUNTS_MASK) :
                           (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -674,7 +681,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
+            if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
                 if (unarrived > 1)
                     return root.internalAwaitAdvance(phase, null);
                 if (root != this)
@@ -689,7 +696,7 @@
                     n |= nextUnarrived;
                 int nextPhase = (phase + 1) & MAX_PHASE;
                 n |= (long)nextPhase << PHASE_SHIFT;
-                if (!STATE.compareAndSet(this, s, n))
+                if (!U.compareAndSwapLong(this, STATE, s, n))
                     return (int)(state >>> PHASE_SHIFT); // terminated
                 releaseWaiters(phase);
                 return nextPhase;
@@ -805,7 +812,7 @@
         final Phaser root = this.root;
         long s;
         while ((s = root.state) >= 0) {
-            if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
+            if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
                 // signal all threads
                 releaseWaiters(0); // Waiters on evenQ
                 releaseWaiters(1); // Waiters on oddQ
@@ -1040,8 +1047,6 @@
                     node = new QNode(this, phase, false, false, 0L);
                     node.wasInterrupted = interrupted;
                 }
-                else
-                    Thread.onSpinWait();
             }
             else if (node.isReleasable()) // done or aborted
                 break;
@@ -1130,14 +1135,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(Phaser.class, "state", long.class);
+            STATE = U.objectFieldOffset
+                (Phaser.class.getDeclaredField("state"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 03a17e5..644de86 100644
--- a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -35,15 +35,12 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.Queue;
 import java.util.SortedSet;
@@ -51,8 +48,10 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
-import jdk.internal.misc.SharedSecrets;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * An unbounded {@linkplain BlockingQueue blocking queue} that uses
@@ -65,15 +64,15 @@
  * non-comparable objects (doing so results in
  * {@code ClassCastException}).
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
- * The Iterator provided in method {@link #iterator()} and the
- * Spliterator provided in method {@link #spliterator()} are <em>not</em>
- * guaranteed to traverse the elements of the PriorityBlockingQueue in
- * any particular order. If you need ordered traversal, consider using
- * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo} can
- * be used to <em>remove</em> some or all elements in priority order and
- * place them in another collection.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the PriorityBlockingQueue in any particular order. If you need
+ * ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo}
+ * can be used to <em>remove</em> some or all elements in priority
+ * order and place them in another collection.
  *
  * <p>Operations on this class make no guarantees about the ordering
  * of elements with equal priority. If you need to enforce an
@@ -102,10 +101,6 @@
  *   }
  * }}</pre>
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -168,12 +163,12 @@
     /**
      * Lock used for all public operations.
      */
-    private final ReentrantLock lock = new ReentrantLock();
+    private final ReentrantLock lock;
 
     /**
      * Condition for blocking when empty.
      */
-    private final Condition notEmpty = lock.newCondition();
+    private final Condition notEmpty;
 
     /**
      * Spinlock for allocation, acquired via CAS.
@@ -225,8 +220,10 @@
                                  Comparator<? super E> comparator) {
         if (initialCapacity < 1)
             throw new IllegalArgumentException();
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
         this.comparator = comparator;
-        this.queue = new Object[Math.max(1, initialCapacity)];
+        this.queue = new Object[initialCapacity];
     }
 
     /**
@@ -246,6 +243,8 @@
      *         of its elements are null
      */
     public PriorityBlockingQueue(Collection<? extends E> c) {
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
         boolean heapify = true; // true if not known to be in heap order
         boolean screen = true;  // true if must screen for nulls
         if (c instanceof SortedSet<?>) {
@@ -261,27 +260,22 @@
             if (pq.getClass() == PriorityBlockingQueue.class) // exact match
                 heapify = false;
         }
-        Object[] es = c.toArray();
-        int n = es.length;
+        Object[] a = c.toArray();
+        int n = a.length;
         // If c.toArray incorrectly doesn't return Object[], copy it.
-        if (es.getClass() != Object[].class)
-            es = Arrays.copyOf(es, n, Object[].class);
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf(a, n, Object[].class);
         if (screen && (n == 1 || this.comparator != null)) {
-            for (Object e : es)
-                if (e == null)
+            for (int i = 0; i < n; ++i)
+                if (a[i] == null)
                     throw new NullPointerException();
         }
-        this.queue = ensureNonEmpty(es);
+        this.queue = a;
         this.size = n;
         if (heapify)
             heapify();
     }
 
-    /** Ensures that queue[0] exists, helping peek() and poll(). */
-    private static Object[] ensureNonEmpty(Object[] es) {
-        return (es.length > 0) ? es : new Object[1];
-    }
-
     /**
      * Tries to grow array to accommodate at least one more element
      * (but normally expand by about 50%), giving up (allowing retry)
@@ -295,7 +289,7 @@
         lock.unlock(); // must release and then re-acquire main lock
         Object[] newArray = null;
         if (allocationSpinLock == 0 &&
-            ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
+            U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
             try {
                 int newCap = oldCap + ((oldCap < 64) ?
                                        (oldCap + 2) : // grow faster if small
@@ -325,23 +319,22 @@
      * Mechanics for poll().  Call only while holding lock.
      */
     private E dequeue() {
-        // assert lock.isHeldByCurrentThread();
-        final Object[] es;
-        final E result;
-
-        if ((result = (E) ((es = queue)[0])) != null) {
-            final int n;
-            final E x = (E) es[(n = --size)];
-            es[n] = null;
-            if (n > 0) {
-                final Comparator<? super E> cmp;
-                if ((cmp = comparator) == null)
-                    siftDownComparable(0, x, es, n);
-                else
-                    siftDownUsingComparator(0, x, es, n, cmp);
-            }
+        int n = size - 1;
+        if (n < 0)
+            return null;
+        else {
+            Object[] array = queue;
+            E result = (E) array[0];
+            E x = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(0, x, array, n);
+            else
+                siftDownUsingComparator(0, x, array, n, cmp);
+            size = n;
+            return result;
         }
-        return result;
     }
 
     /**
@@ -349,38 +342,40 @@
      * promoting x up the tree until it is greater than or equal to
      * its parent, or is the root.
      *
-     * To simplify and speed up coercions and comparisons, the
+     * To simplify and speed up coercions and comparisons. the
      * Comparable and Comparator versions are separated into different
      * methods that are otherwise identical. (Similarly for siftDown.)
+     * These methods are static, with heap state as arguments, to
+     * simplify use in light of possible comparator exceptions.
      *
      * @param k the position to fill
      * @param x the item to insert
-     * @param es the heap array
+     * @param array the heap array
      */
-    private static <T> void siftUpComparable(int k, T x, Object[] es) {
+    private static <T> void siftUpComparable(int k, T x, Object[] array) {
         Comparable<? super T> key = (Comparable<? super T>) x;
         while (k > 0) {
             int parent = (k - 1) >>> 1;
-            Object e = es[parent];
+            Object e = array[parent];
             if (key.compareTo((T) e) >= 0)
                 break;
-            es[k] = e;
+            array[k] = e;
             k = parent;
         }
-        es[k] = key;
+        array[k] = key;
     }
 
-    private static <T> void siftUpUsingComparator(
-        int k, T x, Object[] es, Comparator<? super T> cmp) {
+    private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
+                                       Comparator<? super T> cmp) {
         while (k > 0) {
             int parent = (k - 1) >>> 1;
-            Object e = es[parent];
+            Object e = array[parent];
             if (cmp.compare(x, (T) e) >= 0)
                 break;
-            es[k] = e;
+            array[k] = e;
             k = parent;
         }
-        es[k] = x;
+        array[k] = x;
     }
 
     /**
@@ -390,61 +385,67 @@
      *
      * @param k the position to fill
      * @param x the item to insert
-     * @param es the heap array
+     * @param array the heap array
      * @param n heap size
      */
-    private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
-        // assert n > 0;
-        Comparable<? super T> key = (Comparable<? super T>)x;
-        int half = n >>> 1;           // loop while a non-leaf
-        while (k < half) {
-            int child = (k << 1) + 1; // assume left child is least
-            Object c = es[child];
-            int right = child + 1;
-            if (right < n &&
-                ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
-                c = es[child = right];
-            if (key.compareTo((T) c) <= 0)
-                break;
-            es[k] = c;
-            k = child;
+    private static <T> void siftDownComparable(int k, T x, Object[] array,
+                                               int n) {
+        if (n > 0) {
+            Comparable<? super T> key = (Comparable<? super T>)x;
+            int half = n >>> 1;           // loop while a non-leaf
+            while (k < half) {
+                int child = (k << 1) + 1; // assume left child is least
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n &&
+                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
+                    c = array[child = right];
+                if (key.compareTo((T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = key;
         }
-        es[k] = key;
     }
 
-    private static <T> void siftDownUsingComparator(
-        int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
-        // assert n > 0;
-        int half = n >>> 1;
-        while (k < half) {
-            int child = (k << 1) + 1;
-            Object c = es[child];
-            int right = child + 1;
-            if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
-                c = es[child = right];
-            if (cmp.compare(x, (T) c) <= 0)
-                break;
-            es[k] = c;
-            k = child;
+    private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
+                                                    int n,
+                                                    Comparator<? super T> cmp) {
+        if (n > 0) {
+            int half = n >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
+                    c = array[child = right];
+                if (cmp.compare(x, (T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = x;
         }
-        es[k] = x;
     }
 
     /**
      * Establishes the heap invariant (described above) in the entire tree,
      * assuming nothing about the order of the elements prior to the call.
-     * This classic algorithm due to Floyd (1964) is known to be O(size).
      */
     private void heapify() {
-        final Object[] es = queue;
-        int n = size, i = (n >>> 1) - 1;
-        final Comparator<? super E> cmp;
-        if ((cmp = comparator) == null)
-            for (; i >= 0; i--)
-                siftDownComparable(i, (E) es[i], es, n);
-        else
-            for (; i >= 0; i--)
-                siftDownUsingComparator(i, (E) es[i], es, n, cmp);
+        Object[] array = queue;
+        int n = size;
+        int half = (n >>> 1) - 1;
+        Comparator<? super E> cmp = comparator;
+        if (cmp == null) {
+            for (int i = half; i >= 0; i--)
+                siftDownComparable(i, (E) array[i], array, n);
+        }
+        else {
+            for (int i = half; i >= 0; i--)
+                siftDownUsingComparator(i, (E) array[i], array, n, cmp);
+        }
     }
 
     /**
@@ -478,15 +479,15 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         int n, cap;
-        Object[] es;
-        while ((n = size) >= (cap = (es = queue).length))
-            tryGrow(es, cap);
+        Object[] array;
+        while ((n = size) >= (cap = (array = queue).length))
+            tryGrow(array, cap);
         try {
-            final Comparator<? super E> cmp;
-            if ((cmp = comparator) == null)
-                siftUpComparable(n, e, es);
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftUpComparable(n, e, array);
             else
-                siftUpUsingComparator(n, e, es, cmp);
+                siftUpUsingComparator(n, e, array, cmp);
             size = n + 1;
             notEmpty.signal();
         } finally {
@@ -569,7 +570,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            return (E) queue[0];
+            return (size == 0) ? null : (E) queue[0];
         } finally {
             lock.unlock();
         }
@@ -609,9 +610,10 @@
 
     private int indexOf(Object o) {
         if (o != null) {
-            final Object[] es = queue;
-            for (int i = 0, n = size; i < n; i++)
-                if (o.equals(es[i]))
+            Object[] array = queue;
+            int n = size;
+            for (int i = 0; i < n; i++)
+                if (o.equals(array[i]))
                     return i;
         }
         return -1;
@@ -621,23 +623,23 @@
      * Removes the ith element from queue.
      */
     private void removeAt(int i) {
-        final Object[] es = queue;
-        final int n = size - 1;
+        Object[] array = queue;
+        int n = size - 1;
         if (n == i) // removed last element
-            es[i] = null;
+            array[i] = null;
         else {
-            E moved = (E) es[n];
-            es[n] = null;
-            final Comparator<? super E> cmp;
-            if ((cmp = comparator) == null)
-                siftDownComparable(i, moved, es, n);
+            E moved = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(i, moved, array, n);
             else
-                siftDownUsingComparator(i, moved, es, n, cmp);
-            if (es[i] == moved) {
+                siftDownUsingComparator(i, moved, array, n, cmp);
+            if (array[i] == moved) {
                 if (cmp == null)
-                    siftUpComparable(i, moved, es);
+                    siftUpComparable(i, moved, array);
                 else
-                    siftUpUsingComparator(i, moved, es, cmp);
+                    siftUpUsingComparator(i, moved, array, cmp);
             }
         }
         size = n;
@@ -670,16 +672,14 @@
 
     /**
      * Identity-based version for use in Itr.remove.
-     *
-     * @param o element to be removed from this queue, if present
      */
-    void removeEq(Object o) {
+    void removeEQ(Object o) {
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            final Object[] es = queue;
+            Object[] array = queue;
             for (int i = 0, n = size; i < n; i++) {
-                if (o == es[i]) {
+                if (o == array[i]) {
                     removeAt(i);
                     break;
                 }
@@ -728,7 +728,8 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -755,10 +756,11 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            final Object[] es = queue;
-            for (int i = 0, n = size; i < n; i++)
-                es[i] = null;
+            Object[] array = queue;
+            int n = size;
             size = 0;
+            for (int i = 0; i < n; i++)
+                array[i] = null;
         } finally {
             lock.unlock();
         }
@@ -859,9 +861,10 @@
     final class Itr implements Iterator<E> {
         final Object[] array; // Array of all elements
         int cursor;           // index of next element to return
-        int lastRet = -1;     // index of last element, or -1 if no such
+        int lastRet;          // index of last element, or -1 if no such
 
         Itr(Object[] array) {
+            lastRet = -1;
             this.array = array;
         }
 
@@ -872,28 +875,16 @@
         public E next() {
             if (cursor >= array.length)
                 throw new NoSuchElementException();
-            return (E)array[lastRet = cursor++];
+            lastRet = cursor;
+            return (E)array[cursor++];
         }
 
         public void remove() {
             if (lastRet < 0)
                 throw new IllegalStateException();
-            removeEq(array[lastRet]);
+            removeEQ(array[lastRet]);
             lastRet = -1;
         }
-
-        public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            final Object[] es = array;
-            int i;
-            if ((i = cursor) < es.length) {
-                lastRet = -1;
-                cursor = es.length;
-                for (; i < es.length; i++)
-                    action.accept((E) es[i]);
-                lastRet = es.length - 1;
-            }
-        }
     }
 
     /**
@@ -931,9 +922,7 @@
         throws java.io.IOException, ClassNotFoundException {
         try {
             s.defaultReadObject();
-            int sz = q.size();
-            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, sz);
-            this.queue = new Object[Math.max(1, sz)];
+            this.queue = new Object[q.size()];
             comparator = q.comparator();
             addAll(q);
         } finally {
@@ -941,65 +930,68 @@
         }
     }
 
-    /**
-     * Immutable snapshot spliterator that binds to elements "late".
-     */
-    final class PBQSpliterator implements Spliterator<E> {
-        Object[] array;        // null until late-bound-initialized
+    // Similar to Collections.ArraySnapshotSpliterator but avoids
+    // commitment to toArray until needed
+    static final class PBQSpliterator<E> implements Spliterator<E> {
+        final PriorityBlockingQueue<E> queue;
+        Object[] array;
         int index;
         int fence;
 
-        PBQSpliterator() {}
-
-        PBQSpliterator(Object[] array, int index, int fence) {
+        PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
+                       int index, int fence) {
+            this.queue = queue;
             this.array = array;
             this.index = index;
             this.fence = fence;
         }
 
-        private int getFence() {
-            if (array == null)
-                fence = (array = toArray()).length;
-            return fence;
+        final int getFence() {
+            int hi;
+            if ((hi = fence) < 0)
+                hi = fence = (array = queue.toArray()).length;
+            return hi;
         }
 
-        public PBQSpliterator trySplit() {
+        public PBQSpliterator<E> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
             return (lo >= mid) ? null :
-                new PBQSpliterator(array, lo, index = mid);
+                new PBQSpliterator<E>(queue, array, lo, index = mid);
         }
 
+        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
-            final int hi = getFence(), lo = index;
-            final Object[] es = array;
-            index = hi;                 // ensure exhaustion
-            for (int i = lo; i < hi; i++)
-                action.accept((E) es[i]);
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array) == null)
+                fence = (a = queue.toArray()).length;
+            if ((hi = fence) <= a.length &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((E)a[i]); } while (++i < hi);
+            }
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
-            Objects.requireNonNull(action);
+            if (action == null)
+                throw new NullPointerException();
             if (getFence() > index && index >= 0) {
-                action.accept((E) array[index++]);
+                @SuppressWarnings("unchecked") E e = (E) array[index++];
+                action.accept(e);
                 return true;
             }
             return false;
         }
 
-        public long estimateSize() { return getFence() - index; }
+        public long estimateSize() { return (long)(getFence() - index); }
 
         public int characteristics() {
-            return (Spliterator.NONNULL |
-                    Spliterator.SIZED |
-                    Spliterator.SUBSIZED);
+            return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
         }
     }
 
     /**
      * Returns a {@link Spliterator} over the elements in this queue.
-     * The spliterator does not traverse elements in any particular order
-     * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported).
      *
      * <p>The returned spliterator is
      * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
@@ -1014,106 +1006,18 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new PBQSpliterator();
+        return new PBQSpliterator<E>(this, null, 0, -1);
     }
 
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        return bulkRemove(filter);
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> c.contains(e));
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return bulkRemove(e -> !c.contains(e));
-    }
-
-    // A tiny bit set implementation
-
-    private static long[] nBits(int n) {
-        return new long[((n - 1) >> 6) + 1];
-    }
-    private static void setBit(long[] bits, int i) {
-        bits[i >> 6] |= 1L << i;
-    }
-    private static boolean isClear(long[] bits, int i) {
-        return (bits[i >> 6] & (1L << i)) == 0;
-    }
-
-    /** Implementation of bulk remove methods. */
-    private boolean bulkRemove(Predicate<? super E> filter) {
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            final Object[] es = queue;
-            final int end = size;
-            int i;
-            // Optimize for initial run of survivors
-            for (i = 0; i < end && !filter.test((E) es[i]); i++)
-                ;
-            if (i >= end)
-                return false;
-            // Tolerate predicates that reentrantly access the
-            // collection for read, so traverse once to find elements
-            // to delete, a second pass to physically expunge.
-            final int beg = i;
-            final long[] deathRow = nBits(end - beg);
-            deathRow[0] = 1L;   // set bit 0
-            for (i = beg + 1; i < end; i++)
-                if (filter.test((E) es[i]))
-                    setBit(deathRow, i - beg);
-            int w = beg;
-            for (i = beg; i < end; i++)
-                if (isClear(deathRow, i - beg))
-                    es[w++] = es[i];
-            for (i = size = w; i < end; i++)
-                es[i] = null;
-            heapify();
-            return true;
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * @throws NullPointerException {@inheritDoc}
-     */
-    public void forEach(Consumer<? super E> action) {
-        Objects.requireNonNull(action);
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            final Object[] es = queue;
-            for (int i = 0, n = size; i < n; i++)
-                action.accept((E) es[i]);
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    // VarHandle mechanics
-    private static final VarHandle ALLOCATIONSPINLOCK;
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long ALLOCATIONSPINLOCK;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
-                                                 "allocationSpinLock",
-                                                 int.class);
+            ALLOCATIONSPINLOCK = U.objectFieldOffset
+                (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index be75ff4..6b9fcc3 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -77,11 +77,14 @@
  *     Executors.newScheduledThreadPool(1);
  *
  *   public void beepForAnHour() {
- *     Runnable beeper = () -> System.out.println("beep");
- *     ScheduledFuture<?> beeperHandle =
+ *     final Runnable beeper = new Runnable() {
+ *       public void run() { System.out.println("beep"); }
+ *     };
+ *     final ScheduledFuture&lt;?&lt; beeperHandle =
  *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
- *     Runnable canceller = () -> beeperHandle.cancel(false);
- *     scheduler.schedule(canceller, 1, HOURS);
+ *     scheduler.schedule(new Runnable() {
+ *       public void run() { beeperHandle.cancel(true); }
+ *     }, 60 * 60, SECONDS);
  *   }
  * }}</pre>
  *
@@ -91,7 +94,8 @@
 public interface ScheduledExecutorService extends ExecutorService {
 
     /**
-     * Submits a one-shot task that becomes enabled after the given delay.
+     * Creates and executes a one-shot action that becomes enabled
+     * after the given delay.
      *
      * @param command the task to execute
      * @param delay the time from now to delay execution
@@ -101,14 +105,14 @@
      *         {@code null} upon completion
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command or unit is null
+     * @throws NullPointerException if command is null
      */
     public ScheduledFuture<?> schedule(Runnable command,
                                        long delay, TimeUnit unit);
 
     /**
-     * Submits a value-returning one-shot task that becomes enabled
-     * after the given delay.
+     * Creates and executes a ScheduledFuture that becomes enabled after the
+     * given delay.
      *
      * @param callable the function to execute
      * @param delay the time from now to delay execution
@@ -117,15 +121,15 @@
      * @return a ScheduledFuture that can be used to extract result or cancel
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if callable or unit is null
+     * @throws NullPointerException if callable is null
      */
     public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                            long delay, TimeUnit unit);
 
     /**
-     * Submits a periodic action that becomes enabled first after the
-     * given initial delay, and subsequently with the given period;
-     * that is, executions will commence after
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the given
+     * period; that is, executions will commence after
      * {@code initialDelay}, then {@code initialDelay + period}, then
      * {@code initialDelay + 2 * period}, and so on.
      *
@@ -136,8 +140,8 @@
      * via the returned future.
      * <li>The executor terminates, also resulting in task cancellation.
      * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will throw
-     * {@link ExecutionException}, holding the exception as its cause.
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
      * </ul>
      * Subsequent executions are suppressed.  Subsequent calls to
      * {@link Future#isDone isDone()} on the returned future will
@@ -158,7 +162,7 @@
      *         abnormal termination of a task execution.
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command or unit is null
+     * @throws NullPointerException if command is null
      * @throws IllegalArgumentException if period less than or equal to zero
      */
     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
@@ -167,10 +171,10 @@
                                                   TimeUnit unit);
 
     /**
-     * Submits a periodic action that becomes enabled first after the
-     * given initial delay, and subsequently with the given delay
-     * between the termination of one execution and the commencement of
-     * the next.
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the
+     * given delay between the termination of one execution and the
+     * commencement of the next.
      *
      * <p>The sequence of task executions continues indefinitely until
      * one of the following exceptional completions occur:
@@ -179,8 +183,8 @@
      * via the returned future.
      * <li>The executor terminates, also resulting in task cancellation.
      * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will throw
-     * {@link ExecutionException}, holding the exception as its cause.
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
      * </ul>
      * Subsequent executions are suppressed.  Subsequent calls to
      * {@link Future#isDone isDone()} on the returned future will
@@ -198,7 +202,7 @@
      *         abnormal termination of a task execution.
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command or unit is null
+     * @throws NullPointerException if command is null
      * @throws IllegalArgumentException if delay less than or equal to zero
      */
     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 6aba89a..4249872 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -44,7 +44,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
@@ -90,11 +89,6 @@
  * use {@code allowCoreThreadTimeOut} because this may leave the pool
  * without threads to handle tasks once they become eligible to run.
  *
- * <p>As with {@code ThreadPoolExecutor}, if not otherwise specified,
- * this class uses {@link Executors#defaultThreadFactory} as the
- * default thread factory, and {@link ThreadPoolExecutor.AbortPolicy}
- * as the default rejected execution handler.
- *
  * <p><b>Extension notes:</b> This class overrides the
  * {@link ThreadPoolExecutor#execute(Runnable) execute} and
  * {@link AbstractExecutorService#submit(Runnable) submit}
@@ -169,7 +163,7 @@
     private volatile boolean continueExistingPeriodicTasksAfterShutdown;
 
     /**
-     * False if should cancel non-periodic not-yet-expired tasks on shutdown.
+     * False if should cancel non-periodic tasks on shutdown.
      */
     private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
 
@@ -300,9 +294,10 @@
          * Overrides FutureTask version so as to reset/requeue if periodic.
          */
         public void run() {
-            if (!canRunInCurrentRunState(this))
+            boolean periodic = isPeriodic();
+            if (!canRunInCurrentRunState(periodic))
                 cancel(false);
-            else if (!isPeriodic())
+            else if (!periodic)
                 super.run();
             else if (super.runAndReset()) {
                 setNextRunTime();
@@ -312,18 +307,15 @@
     }
 
     /**
-     * Returns true if can run a task given current run state and
-     * run-after-shutdown parameters.
+     * Returns true if can run a task given current run state
+     * and run-after-shutdown parameters.
+     *
+     * @param periodic true if this task periodic, false if delayed
      */
-    boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
-        if (!isShutdown())
-            return true;
-        if (isStopped())
-            return false;
-        return task.isPeriodic()
-            ? continueExistingPeriodicTasksAfterShutdown
-            : (executeExistingDelayedTasksAfterShutdown
-               || task.getDelay(NANOSECONDS) <= 0);
+    boolean canRunInCurrentRunState(boolean periodic) {
+        return isRunningOrShutdown(periodic ?
+                                   continueExistingPeriodicTasksAfterShutdown :
+                                   executeExistingDelayedTasksAfterShutdown);
     }
 
     /**
@@ -342,7 +334,9 @@
             reject(task);
         else {
             super.getQueue().add(task);
-            if (!canRunInCurrentRunState(task) && remove(task))
+            if (isShutdown() &&
+                !canRunInCurrentRunState(task.isPeriodic()) &&
+                remove(task))
                 task.cancel(false);
             else
                 ensurePrestart();
@@ -356,14 +350,13 @@
      * @param task the task
      */
     void reExecutePeriodic(RunnableScheduledFuture<?> task) {
-        if (canRunInCurrentRunState(task)) {
+        if (canRunInCurrentRunState(true)) {
             super.getQueue().add(task);
-            if (canRunInCurrentRunState(task) || !remove(task)) {
+            if (!canRunInCurrentRunState(true) && remove(task))
+                task.cancel(false);
+            else
                 ensurePrestart();
-                return;
-            }
         }
-        task.cancel(false);
     }
 
     /**
@@ -376,18 +369,23 @@
             getExecuteExistingDelayedTasksAfterShutdownPolicy();
         boolean keepPeriodic =
             getContinueExistingPeriodicTasksAfterShutdownPolicy();
-        // Traverse snapshot to avoid iterator exceptions
-        // TODO: implement and use efficient removeIf
-        // super.getQueue().removeIf(...);
-        for (Object e : q.toArray()) {
-            if (e instanceof RunnableScheduledFuture) {
-                RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e;
-                if ((t.isPeriodic()
-                     ? !keepPeriodic
-                     : (!keepDelayed && t.getDelay(NANOSECONDS) > 0))
-                    || t.isCancelled()) { // also remove if already cancelled
-                    if (q.remove(t))
-                        t.cancel(false);
+        if (!keepDelayed && !keepPeriodic) {
+            for (Object e : q.toArray())
+                if (e instanceof RunnableScheduledFuture<?>)
+                    ((RunnableScheduledFuture<?>) e).cancel(false);
+            q.clear();
+        }
+        else {
+            // Traverse snapshot to avoid iterator exceptions
+            for (Object e : q.toArray()) {
+                if (e instanceof RunnableScheduledFuture) {
+                    RunnableScheduledFuture<?> t =
+                        (RunnableScheduledFuture<?>)e;
+                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
+                        t.isCancelled()) { // also remove if already cancelled
+                        if (q.remove(t))
+                            t.cancel(false);
+                    }
                 }
             }
         }
@@ -583,34 +581,6 @@
     }
 
     /**
-     * Submits a periodic action that becomes enabled first after the
-     * given initial delay, and subsequently with the given period;
-     * that is, executions will commence after
-     * {@code initialDelay}, then {@code initialDelay + period}, then
-     * {@code initialDelay + 2 * period}, and so on.
-     *
-     * <p>The sequence of task executions continues indefinitely until
-     * one of the following exceptional completions occur:
-     * <ul>
-     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
-     * via the returned future.
-     * <li>Method {@link #shutdown} is called and the {@linkplain
-     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
-     * whether to continue after shutdown} is not set true, or method
-     * {@link #shutdownNow} is called; also resulting in task
-     * cancellation.
-     * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will throw
-     * {@link ExecutionException}, holding the exception as its cause.
-     * </ul>
-     * Subsequent executions are suppressed.  Subsequent calls to
-     * {@link Future#isDone isDone()} on the returned future will
-     * return {@code true}.
-     *
-     * <p>If any execution of this task takes longer than its period, then
-     * subsequent executions may start late, but will not concurrently
-     * execute.
-     *
      * @throws RejectedExecutionException {@inheritDoc}
      * @throws NullPointerException       {@inheritDoc}
      * @throws IllegalArgumentException   {@inheritDoc}
@@ -636,29 +606,6 @@
     }
 
     /**
-     * Submits a periodic action that becomes enabled first after the
-     * given initial delay, and subsequently with the given delay
-     * between the termination of one execution and the commencement of
-     * the next.
-     *
-     * <p>The sequence of task executions continues indefinitely until
-     * one of the following exceptional completions occur:
-     * <ul>
-     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
-     * via the returned future.
-     * <li>Method {@link #shutdown} is called and the {@linkplain
-     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
-     * whether to continue after shutdown} is not set true, or method
-     * {@link #shutdownNow} is called; also resulting in task
-     * cancellation.
-     * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will throw
-     * {@link ExecutionException}, holding the exception as its cause.
-     * </ul>
-     * Subsequent executions are suppressed.  Subsequent calls to
-     * {@link Future#isDone isDone()} on the returned future will
-     * return {@code true}.
-     *
      * @throws RejectedExecutionException {@inheritDoc}
      * @throws NullPointerException       {@inheritDoc}
      * @throws IllegalArgumentException   {@inheritDoc}
@@ -736,8 +683,9 @@
     /**
      * Sets the policy on whether to continue executing existing
      * periodic tasks even when this executor has been {@code shutdown}.
-     * In this case, executions will continue until {@code shutdownNow}
-     * or the policy is set to {@code false} when already shutdown.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
      * This value is by default {@code false}.
      *
      * @param value if {@code true}, continue after shutdown, else don't
@@ -752,8 +700,9 @@
     /**
      * Gets the policy on whether to continue executing existing
      * periodic tasks even when this executor has been {@code shutdown}.
-     * In this case, executions will continue until {@code shutdownNow}
-     * or the policy is set to {@code false} when already shutdown.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
      * This value is by default {@code false}.
      *
      * @return {@code true} if will continue after shutdown
@@ -956,7 +905,7 @@
         /**
          * Sets f's heapIndex if it is a ScheduledFutureTask.
          */
-        private static void setIndex(RunnableScheduledFuture<?> f, int idx) {
+        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
             if (f instanceof ScheduledFutureTask)
                 ((ScheduledFutureTask)f).heapIndex = idx;
         }
@@ -1254,12 +1203,41 @@
             }
         }
 
+        /**
+         * Returns first element only if it is expired.
+         * Used only by drainTo.  Call only when holding lock.
+         */
+        private RunnableScheduledFuture<?> peekExpired() {
+            // assert lock.isHeldByCurrentThread();
+            RunnableScheduledFuture<?> first = queue[0];
+            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+                null : first;
+        }
+
         public int drainTo(Collection<? super Runnable> c) {
-            return drainTo(c, Integer.MAX_VALUE);
+            if (c == null)
+                throw new NullPointerException();
+            if (c == this)
+                throw new IllegalArgumentException();
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first;
+                int n = 0;
+                while ((first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
         }
 
         public int drainTo(Collection<? super Runnable> c, int maxElements) {
-            Objects.requireNonNull(c);
+            if (c == null)
+                throw new NullPointerException();
             if (c == this)
                 throw new IllegalArgumentException();
             if (maxElements <= 0)
@@ -1267,11 +1245,9 @@
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
+                RunnableScheduledFuture<?> first;
                 int n = 0;
-                for (RunnableScheduledFuture<?> first;
-                     n < maxElements
-                         && (first = queue[0]) != null
-                         && first.getDelay(NANOSECONDS) <= 0;) {
+                while (n < maxElements && (first = peekExpired()) != null) {
                     c.add(first);   // In this order, in case add() throws.
                     finishPoll(first);
                     ++n;
@@ -1309,13 +1285,7 @@
         }
 
         public Iterator<Runnable> iterator() {
-            final ReentrantLock lock = this.lock;
-            lock.lock();
-            try {
-                return new Itr(Arrays.copyOf(queue, size));
-            } finally {
-                lock.unlock();
-            }
+            return new Itr(Arrays.copyOf(queue, size));
         }
 
         /**
@@ -1337,7 +1307,8 @@
             public Runnable next() {
                 if (cursor >= array.length)
                     throw new NoSuchElementException();
-                return array[lastRet = cursor++];
+                lastRet = cursor;
+                return array[cursor++];
             }
 
             public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Semaphore.java b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
index 86ee638..1298a6e 100644
--- a/ojluni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
@@ -72,8 +72,8 @@
  *   protected synchronized Object getNextAvailableItem() {
  *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
  *       if (!used[i]) {
- *         used[i] = true;
- *         return items[i];
+ *          used[i] = true;
+ *          return items[i];
  *       }
  *     }
  *     return null; // not reached
@@ -82,11 +82,11 @@
  *   protected synchronized boolean markAsUnused(Object item) {
  *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
  *       if (item == items[i]) {
- *         if (used[i]) {
- *           used[i] = false;
- *           return true;
- *         } else
- *           return false;
+ *          if (used[i]) {
+ *            used[i] = false;
+ *            return true;
+ *          } else
+ *            return false;
  *       }
  *     }
  *     return false;
@@ -359,7 +359,7 @@
      * This &quot;barging&quot; behavior can be useful in certain
      * circumstances, even though it breaks fairness. If you want to honor
      * the fairness setting, then use
-     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS)}
+     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
      * which is almost equivalent (it also detects interruption).
      *
      * @return {@code true} if a permit was acquired and {@code false}
@@ -523,7 +523,7 @@
      * &quot;barging&quot; behavior can be useful in certain
      * circumstances, even though it breaks fairness. If you want to
      * honor the fairness setting, then use {@link #tryAcquire(int,
-     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS)}
+     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) }
      * which is almost equivalent (it also detects interruption).
      *
      * @param permits the number of permits to acquire
@@ -631,12 +631,9 @@
     }
 
     /**
-     * Acquires and returns all permits that are immediately
-     * available, or if negative permits are available, releases them.
-     * Upon return, zero permits are available.
+     * Acquires and returns all permits that are immediately available.
      *
-     * @return the number of permits acquired or, if negative, the
-     * number released
+     * @return the number of permits acquired
      */
     public int drainPermits() {
         return sync.drainPermits();
diff --git a/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java b/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
deleted file mode 100644
index 5624161..0000000
--- a/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
+++ /dev/null
@@ -1,1480 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.locks.LockSupport;
-import java.util.function.BiConsumer;
-import java.util.function.BiPredicate;
-import java.util.function.Consumer;
-import static java.util.concurrent.Flow.Publisher;
-import static java.util.concurrent.Flow.Subscriber;
-import static java.util.concurrent.Flow.Subscription;
-
-/**
- * A {@link Flow.Publisher} that asynchronously issues submitted
- * (non-null) items to current subscribers until it is closed.  Each
- * current subscriber receives newly submitted items in the same order
- * unless drops or exceptions are encountered.  Using a
- * SubmissionPublisher allows item generators to act as compliant <a
- * href="http://www.reactive-streams.org/"> reactive-streams</a>
- * Publishers relying on drop handling and/or blocking for flow
- * control.
- *
- * <p>A SubmissionPublisher uses the {@link Executor} supplied in its
- * constructor for delivery to subscribers. The best choice of
- * Executor depends on expected usage. If the generator(s) of
- * submitted items run in separate threads, and the number of
- * subscribers can be estimated, consider using a {@link
- * Executors#newFixedThreadPool}. Otherwise consider using the
- * default, normally the {@link ForkJoinPool#commonPool}.
- *
- * <p>Buffering allows producers and consumers to transiently operate
- * at different rates.  Each subscriber uses an independent buffer.
- * Buffers are created upon first use and expanded as needed up to the
- * given maximum. (The enforced capacity may be rounded up to the
- * nearest power of two and/or bounded by the largest value supported
- * by this implementation.)  Invocations of {@link
- * Flow.Subscription#request(long) request} do not directly result in
- * buffer expansion, but risk saturation if unfilled requests exceed
- * the maximum capacity.  The default value of {@link
- * Flow#defaultBufferSize()} may provide a useful starting point for
- * choosing a capacity based on expected rates, resources, and usages.
- *
- * <p>A single SubmissionPublisher may be shared among multiple
- * sources. Actions in a source thread prior to publishing an item or
- * issuing a signal <a href="package-summary.html#MemoryVisibility">
- * <i>happen-before</i></a> actions subsequent to the corresponding
- * access by each subscriber. But reported estimates of lag and demand
- * are designed for use in monitoring, not for synchronization
- * control, and may reflect stale or inaccurate views of progress.
- *
- * <p>Publication methods support different policies about what to do
- * when buffers are saturated. Method {@link #submit(Object) submit}
- * blocks until resources are available. This is simplest, but least
- * responsive.  The {@code offer} methods may drop items (either
- * immediately or with bounded timeout), but provide an opportunity to
- * interpose a handler and then retry.
- *
- * <p>If any Subscriber method throws an exception, its subscription
- * is cancelled.  If a handler is supplied as a constructor argument,
- * it is invoked before cancellation upon an exception in method
- * {@link Flow.Subscriber#onNext onNext}, but exceptions in methods
- * {@link Flow.Subscriber#onSubscribe onSubscribe},
- * {@link Flow.Subscriber#onError(Throwable) onError} and
- * {@link Flow.Subscriber#onComplete() onComplete} are not recorded or
- * handled before cancellation.  If the supplied Executor throws
- * {@link RejectedExecutionException} (or any other RuntimeException
- * or Error) when attempting to execute a task, or a drop handler
- * throws an exception when processing a dropped item, then the
- * exception is rethrown. In these cases, not all subscribers will
- * have been issued the published item. It is usually good practice to
- * {@link #closeExceptionally closeExceptionally} in these cases.
- *
- * <p>Method {@link #consume(Consumer)} simplifies support for a
- * common case in which the only action of a subscriber is to request
- * and process all items using a supplied function.
- *
- * <p>This class may also serve as a convenient base for subclasses
- * that generate items, and use the methods in this class to publish
- * them.  For example here is a class that periodically publishes the
- * items generated from a supplier. (In practice you might add methods
- * to independently start and stop generation, to share Executors
- * among publishers, and so on, or use a SubmissionPublisher as a
- * component rather than a superclass.)
- *
- * <pre> {@code
- * class PeriodicPublisher<T> extends SubmissionPublisher<T> {
- *   final ScheduledFuture<?> periodicTask;
- *   final ScheduledExecutorService scheduler;
- *   PeriodicPublisher(Executor executor, int maxBufferCapacity,
- *                     Supplier<? extends T> supplier,
- *                     long period, TimeUnit unit) {
- *     super(executor, maxBufferCapacity);
- *     scheduler = new ScheduledThreadPoolExecutor(1);
- *     periodicTask = scheduler.scheduleAtFixedRate(
- *       () -> submit(supplier.get()), 0, period, unit);
- *   }
- *   public void close() {
- *     periodicTask.cancel(false);
- *     scheduler.shutdown();
- *     super.close();
- *   }
- * }}</pre>
- *
- * <p>Here is an example of a {@link Flow.Processor} implementation.
- * It uses single-step requests to its publisher for simplicity of
- * illustration. A more adaptive version could monitor flow using the
- * lag estimate returned from {@code submit}, along with other utility
- * methods.
- *
- * <pre> {@code
- * class TransformProcessor<S,T> extends SubmissionPublisher<T>
- *   implements Flow.Processor<S,T> {
- *   final Function<? super S, ? extends T> function;
- *   Flow.Subscription subscription;
- *   TransformProcessor(Executor executor, int maxBufferCapacity,
- *                      Function<? super S, ? extends T> function) {
- *     super(executor, maxBufferCapacity);
- *     this.function = function;
- *   }
- *   public void onSubscribe(Flow.Subscription subscription) {
- *     (this.subscription = subscription).request(1);
- *   }
- *   public void onNext(S item) {
- *     subscription.request(1);
- *     submit(function.apply(item));
- *   }
- *   public void onError(Throwable ex) { closeExceptionally(ex); }
- *   public void onComplete() { close(); }
- * }}</pre>
- *
- * @param <T> the published item type
- * @author Doug Lea
- * @since 9
- */
-public class SubmissionPublisher<T> implements Publisher<T>,
-                                               AutoCloseable {
-    /*
-     * Most mechanics are handled by BufferedSubscription. This class
-     * mainly tracks subscribers and ensures sequentiality, by using
-     * built-in synchronization locks across public methods. Using
-     * built-in locks works well in the most typical case in which
-     * only one thread submits items. We extend this idea in
-     * submission methods by detecting single-ownership to reduce
-     * producer-consumer synchronization strength.
-     */
-
-    /** The largest possible power of two array size. */
-    static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
-
-    /**
-     * Initial buffer capacity used when maxBufferCapacity is
-     * greater. Must be a power of two.
-     */
-    static final int INITIAL_CAPACITY = 32;
-
-    /** Round capacity to power of 2, at most limit. */
-    static final int roundCapacity(int cap) {
-        int n = cap - 1;
-        n |= n >>> 1;
-        n |= n >>> 2;
-        n |= n >>> 4;
-        n |= n >>> 8;
-        n |= n >>> 16;
-        return (n <= 0) ? 1 : // at least 1
-            (n >= BUFFER_CAPACITY_LIMIT) ? BUFFER_CAPACITY_LIMIT : n + 1;
-    }
-
-    // default Executor setup; nearly the same as CompletableFuture
-
-    /**
-     * Default executor -- ForkJoinPool.commonPool() unless it cannot
-     * support parallelism.
-     */
-    private static final Executor ASYNC_POOL =
-        (ForkJoinPool.getCommonPoolParallelism() > 1) ?
-        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
-
-    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
-    private static final class ThreadPerTaskExecutor implements Executor {
-        ThreadPerTaskExecutor() {}      // prevent access constructor creation
-        public void execute(Runnable r) { new Thread(r).start(); }
-    }
-
-    /**
-     * Clients (BufferedSubscriptions) are maintained in a linked list
-     * (via their "next" fields). This works well for publish loops.
-     * It requires O(n) traversal to check for duplicate subscribers,
-     * but we expect that subscribing is much less common than
-     * publishing. Unsubscribing occurs only during traversal loops,
-     * when BufferedSubscription methods return negative values
-     * signifying that they have been closed.  To reduce
-     * head-of-line blocking, submit and offer methods first call
-     * BufferedSubscription.offer on each subscriber, and place
-     * saturated ones in retries list (using nextRetry field), and
-     * retry, possibly blocking or dropping.
-     */
-    BufferedSubscription<T> clients;
-
-    /** Run status, updated only within locks */
-    volatile boolean closed;
-    /** Set true on first call to subscribe, to initialize possible owner */
-    boolean subscribed;
-    /** The first caller thread to subscribe, or null if thread ever changed */
-    Thread owner;
-    /** If non-null, the exception in closeExceptionally */
-    volatile Throwable closedException;
-
-    // Parameters for constructing BufferedSubscriptions
-    final Executor executor;
-    final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
-    final int maxBufferCapacity;
-
-    /**
-     * Creates a new SubmissionPublisher using the given Executor for
-     * async delivery to subscribers, with the given maximum buffer size
-     * for each subscriber, and, if non-null, the given handler invoked
-     * when any Subscriber throws an exception in method {@link
-     * Flow.Subscriber#onNext(Object) onNext}.
-     *
-     * @param executor the executor to use for async delivery,
-     * supporting creation of at least one independent thread
-     * @param maxBufferCapacity the maximum capacity for each
-     * subscriber's buffer (the enforced capacity may be rounded up to
-     * the nearest power of two and/or bounded by the largest value
-     * supported by this implementation; method {@link #getMaxBufferCapacity}
-     * returns the actual value)
-     * @param handler if non-null, procedure to invoke upon exception
-     * thrown in method {@code onNext}
-     * @throws NullPointerException if executor is null
-     * @throws IllegalArgumentException if maxBufferCapacity not
-     * positive
-     */
-    public SubmissionPublisher(Executor executor, int maxBufferCapacity,
-                               BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler) {
-        if (executor == null)
-            throw new NullPointerException();
-        if (maxBufferCapacity <= 0)
-            throw new IllegalArgumentException("capacity must be positive");
-        this.executor = executor;
-        this.onNextHandler = handler;
-        this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
-    }
-
-    /**
-     * Creates a new SubmissionPublisher using the given Executor for
-     * async delivery to subscribers, with the given maximum buffer size
-     * for each subscriber, and no handler for Subscriber exceptions in
-     * method {@link Flow.Subscriber#onNext(Object) onNext}.
-     *
-     * @param executor the executor to use for async delivery,
-     * supporting creation of at least one independent thread
-     * @param maxBufferCapacity the maximum capacity for each
-     * subscriber's buffer (the enforced capacity may be rounded up to
-     * the nearest power of two and/or bounded by the largest value
-     * supported by this implementation; method {@link #getMaxBufferCapacity}
-     * returns the actual value)
-     * @throws NullPointerException if executor is null
-     * @throws IllegalArgumentException if maxBufferCapacity not
-     * positive
-     */
-    public SubmissionPublisher(Executor executor, int maxBufferCapacity) {
-        this(executor, maxBufferCapacity, null);
-    }
-
-    /**
-     * Creates a new SubmissionPublisher using the {@link
-     * ForkJoinPool#commonPool()} for async delivery to subscribers
-     * (unless it does not support a parallelism level of at least two,
-     * in which case, a new Thread is created to run each task), with
-     * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no
-     * handler for Subscriber exceptions in method {@link
-     * Flow.Subscriber#onNext(Object) onNext}.
-     */
-    public SubmissionPublisher() {
-        this(ASYNC_POOL, Flow.defaultBufferSize(), null);
-    }
-
-    /**
-     * Adds the given Subscriber unless already subscribed.  If already
-     * subscribed, the Subscriber's {@link
-     * Flow.Subscriber#onError(Throwable) onError} method is invoked on
-     * the existing subscription with an {@link IllegalStateException}.
-     * Otherwise, upon success, the Subscriber's {@link
-     * Flow.Subscriber#onSubscribe onSubscribe} method is invoked
-     * asynchronously with a new {@link Flow.Subscription}.  If {@link
-     * Flow.Subscriber#onSubscribe onSubscribe} throws an exception, the
-     * subscription is cancelled. Otherwise, if this SubmissionPublisher
-     * was closed exceptionally, then the subscriber's {@link
-     * Flow.Subscriber#onError onError} method is invoked with the
-     * corresponding exception, or if closed without exception, the
-     * subscriber's {@link Flow.Subscriber#onComplete() onComplete}
-     * method is invoked.  Subscribers may enable receiving items by
-     * invoking the {@link Flow.Subscription#request(long) request}
-     * method of the new Subscription, and may unsubscribe by invoking
-     * its {@link Flow.Subscription#cancel() cancel} method.
-     *
-     * @param subscriber the subscriber
-     * @throws NullPointerException if subscriber is null
-     */
-    public void subscribe(Subscriber<? super T> subscriber) {
-        if (subscriber == null) throw new NullPointerException();
-        int max = maxBufferCapacity; // allocate initial array
-        Object[] array = new Object[max < INITIAL_CAPACITY ?
-                                    max : INITIAL_CAPACITY];
-        BufferedSubscription<T> subscription =
-            new BufferedSubscription<T>(subscriber, executor, onNextHandler,
-                                        array, max);
-        synchronized (this) {
-            if (!subscribed) {
-                subscribed = true;
-                owner = Thread.currentThread();
-            }
-            for (BufferedSubscription<T> b = clients, pred = null;;) {
-                if (b == null) {
-                    Throwable ex;
-                    subscription.onSubscribe();
-                    if ((ex = closedException) != null)
-                        subscription.onError(ex);
-                    else if (closed)
-                        subscription.onComplete();
-                    else if (pred == null)
-                        clients = subscription;
-                    else
-                        pred.next = subscription;
-                    break;
-                }
-                BufferedSubscription<T> next = b.next;
-                if (b.isClosed()) {   // remove
-                    b.next = null;    // detach
-                    if (pred == null)
-                        clients = next;
-                    else
-                        pred.next = next;
-                }
-                else if (subscriber.equals(b.subscriber)) {
-                    b.onError(new IllegalStateException("Duplicate subscribe"));
-                    break;
-                }
-                else
-                    pred = b;
-                b = next;
-            }
-        }
-    }
-
-    /**
-     * Common implementation for all three forms of submit and offer.
-     * Acts as submit if nanos == Long.MAX_VALUE, else offer.
-     */
-    private int doOffer(T item, long nanos,
-                        BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
-        if (item == null) throw new NullPointerException();
-        int lag = 0;
-        boolean complete, unowned;
-        synchronized (this) {
-            Thread t = Thread.currentThread(), o;
-            BufferedSubscription<T> b = clients;
-            if ((unowned = ((o = owner) != t)) && o != null)
-                owner = null;                     // disable bias
-            if (b == null)
-                complete = closed;
-            else {
-                complete = false;
-                boolean cleanMe = false;
-                BufferedSubscription<T> retries = null, rtail = null, next;
-                do {
-                    next = b.next;
-                    int stat = b.offer(item, unowned);
-                    if (stat == 0) {              // saturated; add to retry list
-                        b.nextRetry = null;       // avoid garbage on exceptions
-                        if (rtail == null)
-                            retries = b;
-                        else
-                            rtail.nextRetry = b;
-                        rtail = b;
-                    }
-                    else if (stat < 0)            // closed
-                        cleanMe = true;           // remove later
-                    else if (stat > lag)
-                        lag = stat;
-                } while ((b = next) != null);
-
-                if (retries != null || cleanMe)
-                    lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
-            }
-        }
-        if (complete)
-            throw new IllegalStateException("Closed");
-        else
-            return lag;
-    }
-
-    /**
-     * Helps, (timed) waits for, and/or drops buffers on list; returns
-     * lag or negative drops (for use in offer).
-     */
-    private int retryOffer(T item, long nanos,
-                           BiPredicate<Subscriber<? super T>, ? super T> onDrop,
-                           BufferedSubscription<T> retries, int lag,
-                           boolean cleanMe) {
-        for (BufferedSubscription<T> r = retries; r != null;) {
-            BufferedSubscription<T> nextRetry = r.nextRetry;
-            r.nextRetry = null;
-            if (nanos > 0L)
-                r.awaitSpace(nanos);
-            int stat = r.retryOffer(item);
-            if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
-                stat = r.retryOffer(item);
-            if (stat == 0)
-                lag = (lag >= 0) ? -1 : lag - 1;
-            else if (stat < 0)
-                cleanMe = true;
-            else if (lag >= 0 && stat > lag)
-                lag = stat;
-            r = nextRetry;
-        }
-        if (cleanMe)
-            cleanAndCount();
-        return lag;
-    }
-
-    /**
-     * Returns current list count after removing closed subscribers.
-     * Call only while holding lock.  Used mainly by retryOffer for
-     * cleanup.
-     */
-    private int cleanAndCount() {
-        int count = 0;
-        BufferedSubscription<T> pred = null, next;
-        for (BufferedSubscription<T> b = clients; b != null; b = next) {
-            next = b.next;
-            if (b.isClosed()) {
-                b.next = null;
-                if (pred == null)
-                    clients = next;
-                else
-                    pred.next = next;
-            }
-            else {
-                pred = b;
-                ++count;
-            }
-        }
-        return count;
-    }
-
-    /**
-     * Publishes the given item to each current subscriber by
-     * asynchronously invoking its {@link Flow.Subscriber#onNext(Object)
-     * onNext} method, blocking uninterruptibly while resources for any
-     * subscriber are unavailable. This method returns an estimate of
-     * the maximum lag (number of items submitted but not yet consumed)
-     * among all current subscribers. This value is at least one
-     * (accounting for this submitted item) if there are any
-     * subscribers, else zero.
-     *
-     * <p>If the Executor for this publisher throws a
-     * RejectedExecutionException (or any other RuntimeException or
-     * Error) when attempting to asynchronously notify subscribers,
-     * then this exception is rethrown, in which case not all
-     * subscribers will have been issued this item.
-     *
-     * @param item the (non-null) item to publish
-     * @return the estimated maximum lag among subscribers
-     * @throws IllegalStateException if closed
-     * @throws NullPointerException if item is null
-     * @throws RejectedExecutionException if thrown by Executor
-     */
-    public int submit(T item) {
-        return doOffer(item, Long.MAX_VALUE, null);
-    }
-
-    /**
-     * Publishes the given item, if possible, to each current subscriber
-     * by asynchronously invoking its {@link
-     * Flow.Subscriber#onNext(Object) onNext} method. The item may be
-     * dropped by one or more subscribers if resource limits are
-     * exceeded, in which case the given handler (if non-null) is
-     * invoked, and if it returns true, retried once.  Other calls to
-     * methods in this class by other threads are blocked while the
-     * handler is invoked.  Unless recovery is assured, options are
-     * usually limited to logging the error and/or issuing an {@link
-     * Flow.Subscriber#onError(Throwable) onError} signal to the
-     * subscriber.
-     *
-     * <p>This method returns a status indicator: If negative, it
-     * represents the (negative) number of drops (failed attempts to
-     * issue the item to a subscriber). Otherwise it is an estimate of
-     * the maximum lag (number of items submitted but not yet
-     * consumed) among all current subscribers. This value is at least
-     * one (accounting for this submitted item) if there are any
-     * subscribers, else zero.
-     *
-     * <p>If the Executor for this publisher throws a
-     * RejectedExecutionException (or any other RuntimeException or
-     * Error) when attempting to asynchronously notify subscribers, or
-     * the drop handler throws an exception when processing a dropped
-     * item, then this exception is rethrown.
-     *
-     * @param item the (non-null) item to publish
-     * @param onDrop if non-null, the handler invoked upon a drop to a
-     * subscriber, with arguments of the subscriber and item; if it
-     * returns true, an offer is re-attempted (once)
-     * @return if negative, the (negative) number of drops; otherwise
-     * an estimate of maximum lag
-     * @throws IllegalStateException if closed
-     * @throws NullPointerException if item is null
-     * @throws RejectedExecutionException if thrown by Executor
-     */
-    public int offer(T item,
-                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
-        return doOffer(item, 0L, onDrop);
-    }
-
-    /**
-     * Publishes the given item, if possible, to each current subscriber
-     * by asynchronously invoking its {@link
-     * Flow.Subscriber#onNext(Object) onNext} method, blocking while
-     * resources for any subscription are unavailable, up to the
-     * specified timeout or until the caller thread is interrupted, at
-     * which point the given handler (if non-null) is invoked, and if it
-     * returns true, retried once. (The drop handler may distinguish
-     * timeouts from interrupts by checking whether the current thread
-     * is interrupted.)  Other calls to methods in this class by other
-     * threads are blocked while the handler is invoked.  Unless
-     * recovery is assured, options are usually limited to logging the
-     * error and/or issuing an {@link Flow.Subscriber#onError(Throwable)
-     * onError} signal to the subscriber.
-     *
-     * <p>This method returns a status indicator: If negative, it
-     * represents the (negative) number of drops (failed attempts to
-     * issue the item to a subscriber). Otherwise it is an estimate of
-     * the maximum lag (number of items submitted but not yet
-     * consumed) among all current subscribers. This value is at least
-     * one (accounting for this submitted item) if there are any
-     * subscribers, else zero.
-     *
-     * <p>If the Executor for this publisher throws a
-     * RejectedExecutionException (or any other RuntimeException or
-     * Error) when attempting to asynchronously notify subscribers, or
-     * the drop handler throws an exception when processing a dropped
-     * item, then this exception is rethrown.
-     *
-     * @param item the (non-null) item to publish
-     * @param timeout how long to wait for resources for any subscriber
-     * before giving up, in units of {@code unit}
-     * @param unit a {@code TimeUnit} determining how to interpret the
-     * {@code timeout} parameter
-     * @param onDrop if non-null, the handler invoked upon a drop to a
-     * subscriber, with arguments of the subscriber and item; if it
-     * returns true, an offer is re-attempted (once)
-     * @return if negative, the (negative) number of drops; otherwise
-     * an estimate of maximum lag
-     * @throws IllegalStateException if closed
-     * @throws NullPointerException if item is null
-     * @throws RejectedExecutionException if thrown by Executor
-     */
-    public int offer(T item, long timeout, TimeUnit unit,
-                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
-        long nanos = unit.toNanos(timeout);
-        // distinguishes from untimed (only wrt interrupt policy)
-        if (nanos == Long.MAX_VALUE) --nanos;
-        return doOffer(item, nanos, onDrop);
-    }
-
-    /**
-     * Unless already closed, issues {@link
-     * Flow.Subscriber#onComplete() onComplete} signals to current
-     * subscribers, and disallows subsequent attempts to publish.
-     * Upon return, this method does <em>NOT</em> guarantee that all
-     * subscribers have yet completed.
-     */
-    public void close() {
-        if (!closed) {
-            BufferedSubscription<T> b;
-            synchronized (this) {
-                // no need to re-check closed here
-                b = clients;
-                clients = null;
-                owner = null;
-                closed = true;
-            }
-            while (b != null) {
-                BufferedSubscription<T> next = b.next;
-                b.next = null;
-                b.onComplete();
-                b = next;
-            }
-        }
-    }
-
-    /**
-     * Unless already closed, issues {@link
-     * Flow.Subscriber#onError(Throwable) onError} signals to current
-     * subscribers with the given error, and disallows subsequent
-     * attempts to publish.  Future subscribers also receive the given
-     * error. Upon return, this method does <em>NOT</em> guarantee
-     * that all subscribers have yet completed.
-     *
-     * @param error the {@code onError} argument sent to subscribers
-     * @throws NullPointerException if error is null
-     */
-    public void closeExceptionally(Throwable error) {
-        if (error == null)
-            throw new NullPointerException();
-        if (!closed) {
-            BufferedSubscription<T> b;
-            synchronized (this) {
-                b = clients;
-                if (!closed) {  // don't clobber racing close
-                    closedException = error;
-                    clients = null;
-                    owner = null;
-                    closed = true;
-                }
-            }
-            while (b != null) {
-                BufferedSubscription<T> next = b.next;
-                b.next = null;
-                b.onError(error);
-                b = next;
-            }
-        }
-    }
-
-    /**
-     * Returns true if this publisher is not accepting submissions.
-     *
-     * @return true if closed
-     */
-    public boolean isClosed() {
-        return closed;
-    }
-
-    /**
-     * Returns the exception associated with {@link
-     * #closeExceptionally(Throwable) closeExceptionally}, or null if
-     * not closed or if closed normally.
-     *
-     * @return the exception, or null if none
-     */
-    public Throwable getClosedException() {
-        return closedException;
-    }
-
-    /**
-     * Returns true if this publisher has any subscribers.
-     *
-     * @return true if this publisher has any subscribers
-     */
-    public boolean hasSubscribers() {
-        boolean nonEmpty = false;
-        synchronized (this) {
-            for (BufferedSubscription<T> b = clients; b != null;) {
-                BufferedSubscription<T> next = b.next;
-                if (b.isClosed()) {
-                    b.next = null;
-                    b = clients = next;
-                }
-                else {
-                    nonEmpty = true;
-                    break;
-                }
-            }
-        }
-        return nonEmpty;
-    }
-
-    /**
-     * Returns the number of current subscribers.
-     *
-     * @return the number of current subscribers
-     */
-    public int getNumberOfSubscribers() {
-        synchronized (this) {
-            return cleanAndCount();
-        }
-    }
-
-    /**
-     * Returns the Executor used for asynchronous delivery.
-     *
-     * @return the Executor used for asynchronous delivery
-     */
-    public Executor getExecutor() {
-        return executor;
-    }
-
-    /**
-     * Returns the maximum per-subscriber buffer capacity.
-     *
-     * @return the maximum per-subscriber buffer capacity
-     */
-    public int getMaxBufferCapacity() {
-        return maxBufferCapacity;
-    }
-
-    /**
-     * Returns a list of current subscribers for monitoring and
-     * tracking purposes, not for invoking {@link Flow.Subscriber}
-     * methods on the subscribers.
-     *
-     * @return list of current subscribers
-     */
-    public List<Subscriber<? super T>> getSubscribers() {
-        ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
-        synchronized (this) {
-            BufferedSubscription<T> pred = null, next;
-            for (BufferedSubscription<T> b = clients; b != null; b = next) {
-                next = b.next;
-                if (b.isClosed()) {
-                    b.next = null;
-                    if (pred == null)
-                        clients = next;
-                    else
-                        pred.next = next;
-                }
-                else {
-                    subs.add(b.subscriber);
-                    pred = b;
-                }
-            }
-        }
-        return subs;
-    }
-
-    /**
-     * Returns true if the given Subscriber is currently subscribed.
-     *
-     * @param subscriber the subscriber
-     * @return true if currently subscribed
-     * @throws NullPointerException if subscriber is null
-     */
-    public boolean isSubscribed(Subscriber<? super T> subscriber) {
-        if (subscriber == null) throw new NullPointerException();
-        if (!closed) {
-            synchronized (this) {
-                BufferedSubscription<T> pred = null, next;
-                for (BufferedSubscription<T> b = clients; b != null; b = next) {
-                    next = b.next;
-                    if (b.isClosed()) {
-                        b.next = null;
-                        if (pred == null)
-                            clients = next;
-                        else
-                            pred.next = next;
-                    }
-                    else if (subscriber.equals(b.subscriber))
-                        return true;
-                    else
-                        pred = b;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns an estimate of the minimum number of items requested
-     * (via {@link Flow.Subscription#request(long) request}) but not
-     * yet produced, among all current subscribers.
-     *
-     * @return the estimate, or zero if no subscribers
-     */
-    public long estimateMinimumDemand() {
-        long min = Long.MAX_VALUE;
-        boolean nonEmpty = false;
-        synchronized (this) {
-            BufferedSubscription<T> pred = null, next;
-            for (BufferedSubscription<T> b = clients; b != null; b = next) {
-                int n; long d;
-                next = b.next;
-                if ((n = b.estimateLag()) < 0) {
-                    b.next = null;
-                    if (pred == null)
-                        clients = next;
-                    else
-                        pred.next = next;
-                }
-                else {
-                    if ((d = b.demand - n) < min)
-                        min = d;
-                    nonEmpty = true;
-                    pred = b;
-                }
-            }
-        }
-        return nonEmpty ? min : 0;
-    }
-
-    /**
-     * Returns an estimate of the maximum number of items produced but
-     * not yet consumed among all current subscribers.
-     *
-     * @return the estimate
-     */
-    public int estimateMaximumLag() {
-        int max = 0;
-        synchronized (this) {
-            BufferedSubscription<T> pred = null, next;
-            for (BufferedSubscription<T> b = clients; b != null; b = next) {
-                int n;
-                next = b.next;
-                if ((n = b.estimateLag()) < 0) {
-                    b.next = null;
-                    if (pred == null)
-                        clients = next;
-                    else
-                        pred.next = next;
-                }
-                else {
-                    if (n > max)
-                        max = n;
-                    pred = b;
-                }
-            }
-        }
-        return max;
-    }
-
-    /**
-     * Processes all published items using the given Consumer function.
-     * Returns a CompletableFuture that is completed normally when this
-     * publisher signals {@link Flow.Subscriber#onComplete()
-     * onComplete}, or completed exceptionally upon any error, or an
-     * exception is thrown by the Consumer, or the returned
-     * CompletableFuture is cancelled, in which case no further items
-     * are processed.
-     *
-     * @param consumer the function applied to each onNext item
-     * @return a CompletableFuture that is completed normally
-     * when the publisher signals onComplete, and exceptionally
-     * upon any error or cancellation
-     * @throws NullPointerException if consumer is null
-     */
-    public CompletableFuture<Void> consume(Consumer<? super T> consumer) {
-        if (consumer == null)
-            throw new NullPointerException();
-        CompletableFuture<Void> status = new CompletableFuture<>();
-        subscribe(new ConsumerSubscriber<T>(status, consumer));
-        return status;
-    }
-
-    /** Subscriber for method consume */
-    static final class ConsumerSubscriber<T> implements Subscriber<T> {
-        final CompletableFuture<Void> status;
-        final Consumer<? super T> consumer;
-        Subscription subscription;
-        ConsumerSubscriber(CompletableFuture<Void> status,
-                           Consumer<? super T> consumer) {
-            this.status = status; this.consumer = consumer;
-        }
-        public final void onSubscribe(Subscription subscription) {
-            this.subscription = subscription;
-            status.whenComplete((v, e) -> subscription.cancel());
-            if (!status.isDone())
-                subscription.request(Long.MAX_VALUE);
-        }
-        public final void onError(Throwable ex) {
-            status.completeExceptionally(ex);
-        }
-        public final void onComplete() {
-            status.complete(null);
-        }
-        public final void onNext(T item) {
-            try {
-                consumer.accept(item);
-            } catch (Throwable ex) {
-                subscription.cancel();
-                status.completeExceptionally(ex);
-            }
-        }
-    }
-
-    /**
-     * A task for consuming buffer items and signals, created and
-     * executed whenever they become available. A task consumes as
-     * many items/signals as possible before terminating, at which
-     * point another task is created when needed. The dual Runnable
-     * and ForkJoinTask declaration saves overhead when executed by
-     * ForkJoinPools, without impacting other kinds of Executors.
-     */
-    @SuppressWarnings("serial")
-    static final class ConsumerTask<T> extends ForkJoinTask<Void>
-        implements Runnable, CompletableFuture.AsynchronousCompletionTask {
-        final BufferedSubscription<T> consumer;
-        ConsumerTask(BufferedSubscription<T> consumer) {
-            this.consumer = consumer;
-        }
-        public final Void getRawResult() { return null; }
-        public final void setRawResult(Void v) {}
-        public final boolean exec() { consumer.consume(); return false; }
-        public final void run() { consumer.consume(); }
-    }
-
-    /**
-     * A resizable array-based ring buffer with integrated control to
-     * start a consumer task whenever items are available.  The buffer
-     * algorithm is specialized for the case of at most one concurrent
-     * producer and consumer, and power of two buffer sizes. It relies
-     * primarily on atomic operations (CAS or getAndSet) at the next
-     * array slot to put or take an element, at the "tail" and "head"
-     * indices written only by the producer and consumer respectively.
-     *
-     * We ensure internally that there is at most one active consumer
-     * task at any given time. The publisher guarantees a single
-     * producer via its lock. Sync among producers and consumers
-     * relies on volatile fields "ctl", "demand", and "waiting" (along
-     * with element access). Other variables are accessed in plain
-     * mode, relying on outer ordering and exclusion, and/or enclosing
-     * them within other volatile accesses. Some atomic operations are
-     * avoided by tracking single threaded ownership by producers (in
-     * the style of biased locking).
-     *
-     * Execution control and protocol state are managed using field
-     * "ctl".  Methods to subscribe, close, request, and cancel set
-     * ctl bits (mostly using atomic boolean method getAndBitwiseOr),
-     * and ensure that a task is running. (The corresponding consumer
-     * side actions are in method consume.)  To avoid starting a new
-     * task on each action, ctl also includes a keep-alive bit
-     * (ACTIVE) that is refreshed if needed on producer actions.
-     * (Maintaining agreement about keep-alives requires most atomic
-     * updates to be full SC/Volatile strength, which is still much
-     * cheaper than using one task per item.)  Error signals
-     * additionally null out items and/or fields to reduce termination
-     * latency.  The cancel() method is supported by treating as ERROR
-     * but suppressing onError signal.
-     *
-     * Support for blocking also exploits the fact that there is only
-     * one possible waiter. ManagedBlocker-compatible control fields
-     * are placed in this class itself rather than in wait-nodes.
-     * Blocking control relies on the "waiting" and "waiter"
-     * fields. Producers set them before trying to block. Signalling
-     * unparks and clears fields. If the producer and/or consumer are
-     * using a ForkJoinPool, the producer attempts to help run
-     * consumer tasks via ForkJoinPool.helpAsyncBlocker before
-     * blocking.
-     *
-     * Usages of this class may encounter any of several forms of
-     * memory contention. We try to ameliorate across them without
-     * unduly impacting footprints in low-contention usages where it
-     * isn't needed. Buffer arrays start out small and grow only as
-     * needed.  The class uses @Contended and heuristic field
-     * declaration ordering to reduce false-sharing memory contention
-     * across instances of BufferedSubscription (as in, multiple
-     * subscribers per publisher).  We additionally segregate some
-     * fields that would otherwise nearly always encounter cache line
-     * contention among producers and consumers. To reduce contention
-     * across time (vs space), consumers only periodically update
-     * other fields (see method takeItems), at the expense of possibly
-     * staler reporting of lags and demand (bounded at 12.5% == 1/8
-     * capacity) and possibly more atomic operations.
-     *
-     * Other forms of imbalance and slowdowns can occur during startup
-     * when producer and consumer methods are compiled and/or memory
-     * is allocated at different rates.  This is ameliorated by
-     * artificially subdividing some consumer methods, including
-     * isolation of all subscriber callbacks.  This code also includes
-     * typical power-of-two array screening idioms to avoid compilers
-     * generating traps, along with the usual SSA-based inline
-     * assignment coding style. Also, all methods and fields have
-     * default visibility to simplify usage by callers.
-     */
-    @SuppressWarnings("serial")
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    // @jdk.internal.vm.annotation.Contended
-    static final class BufferedSubscription<T>
-        implements Subscription, ForkJoinPool.ManagedBlocker {
-        long timeout;                      // Long.MAX_VALUE if untimed wait
-        int head;                          // next position to take
-        int tail;                          // next position to put
-        final int maxCapacity;             // max buffer size
-        volatile int ctl;                  // atomic run state flags
-        Object[] array;                    // buffer
-        final Subscriber<? super T> subscriber;
-        final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
-        Executor executor;                 // null on error
-        Thread waiter;                     // blocked producer thread
-        Throwable pendingError;            // holds until onError issued
-        BufferedSubscription<T> next;      // used only by publisher
-        BufferedSubscription<T> nextRetry; // used only by publisher
-
-        // Android-removed: @Contended, this hint is not used by the Android runtime.
-        // @jdk.internal.vm.annotation.Contended("c") // segregate
-        volatile long demand;              // # unfilled requests
-        // Android-removed: @Contended, this hint is not used by the Android runtime.
-        // @jdk.internal.vm.annotation.Contended("c")
-        volatile int waiting;              // nonzero if producer blocked
-
-        // ctl bit values
-        static final int CLOSED   = 0x01;  // if set, other bits ignored
-        static final int ACTIVE   = 0x02;  // keep-alive for consumer task
-        static final int REQS     = 0x04;  // (possibly) nonzero demand
-        static final int ERROR    = 0x08;  // issues onError when noticed
-        static final int COMPLETE = 0x10;  // issues onComplete when done
-        static final int RUN      = 0x20;  // task is or will be running
-        static final int OPEN     = 0x40;  // true after subscribe
-
-        static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
-
-        BufferedSubscription(Subscriber<? super T> subscriber,
-                             Executor executor,
-                             BiConsumer<? super Subscriber<? super T>,
-                             ? super Throwable> onNextHandler,
-                             Object[] array,
-                             int maxBufferCapacity) {
-            this.subscriber = subscriber;
-            this.executor = executor;
-            this.onNextHandler = onNextHandler;
-            this.array = array;
-            this.maxCapacity = maxBufferCapacity;
-        }
-
-        // Wrappers for some VarHandle methods
-
-        final boolean weakCasCtl(int cmp, int val) {
-            return CTL.weakCompareAndSet(this, cmp, val);
-        }
-
-        final int getAndBitwiseOrCtl(int bits) {
-            return (int)CTL.getAndBitwiseOr(this, bits);
-        }
-
-        final long subtractDemand(int k) {
-            long n = (long)(-k);
-            return n + (long)DEMAND.getAndAdd(this, n);
-        }
-
-        final boolean casDemand(long cmp, long val) {
-            return DEMAND.compareAndSet(this, cmp, val);
-        }
-
-        // Utilities used by SubmissionPublisher
-
-        /**
-         * Returns true if closed (consumer task may still be running).
-         */
-        final boolean isClosed() {
-            return (ctl & CLOSED) != 0;
-        }
-
-        /**
-         * Returns estimated number of buffered items, or negative if
-         * closed.
-         */
-        final int estimateLag() {
-            int c = ctl, n = tail - head;
-            return ((c & CLOSED) != 0) ? -1 : (n < 0) ? 0 : n;
-        }
-
-        // Methods for submitting items
-
-        /**
-         * Tries to add item and start consumer task if necessary.
-         * @return negative if closed, 0 if saturated, else estimated lag
-         */
-        final int offer(T item, boolean unowned) {
-            Object[] a;
-            int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
-            int t = tail, i = t & (cap - 1), n = t + 1 - head;
-            if (cap > 0) {
-                boolean added;
-                if (n >= cap && cap < maxCapacity) // resize
-                    added = growAndOffer(item, a, t);
-                else if (n >= cap || unowned)      // need volatile CAS
-                    added = QA.compareAndSet(a, i, null, item);
-                else {                             // can use release mode
-                    QA.setRelease(a, i, item);
-                    added = true;
-                }
-                if (added) {
-                    tail = t + 1;
-                    stat = n;
-                }
-            }
-            return startOnOffer(stat);
-        }
-
-        /**
-         * Tries to expand buffer and add item, returning true on
-         * success. Currently fails only if out of memory.
-         */
-        final boolean growAndOffer(T item, Object[] a, int t) {
-            int cap = 0, newCap = 0;
-            Object[] newArray = null;
-            if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
-                try {
-                    newArray = new Object[newCap];
-                } catch (OutOfMemoryError ex) {
-                }
-            }
-            if (newArray == null)
-                return false;
-            else {                                // take and move items
-                int newMask = newCap - 1;
-                newArray[t-- & newMask] = item;
-                for (int mask = cap - 1, k = mask; k >= 0; --k) {
-                    Object x = QA.getAndSet(a, t & mask, null);
-                    if (x == null)
-                        break;                    // already consumed
-                    else
-                        newArray[t-- & newMask] = x;
-                }
-                array = newArray;
-                VarHandle.releaseFence();         // release array and slots
-                return true;
-            }
-        }
-
-        /**
-         * Version of offer for retries (no resize or bias)
-         */
-        final int retryOffer(T item) {
-            Object[] a;
-            int stat = 0, t = tail, h = head, cap;
-            if ((a = array) != null && (cap = a.length) > 0 &&
-                QA.compareAndSet(a, (cap - 1) & t, null, item))
-                stat = (tail = t + 1) - h;
-            return startOnOffer(stat);
-        }
-
-        /**
-         * Tries to start consumer task after offer.
-         * @return negative if now closed, else argument
-         */
-        final int startOnOffer(int stat) {
-            int c; // start or keep alive if requests exist and not active
-            if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
-                ((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
-                tryStart();
-            else if ((c & CLOSED) != 0)
-                stat = -1;
-            return stat;
-        }
-
-        /**
-         * Tries to start consumer task. Sets error state on failure.
-         */
-        final void tryStart() {
-            try {
-                Executor e;
-                ConsumerTask<T> task = new ConsumerTask<T>(this);
-                if ((e = executor) != null)   // skip if disabled on error
-                    e.execute(task);
-            } catch (RuntimeException | Error ex) {
-                getAndBitwiseOrCtl(ERROR | CLOSED);
-                throw ex;
-            }
-        }
-
-        // Signals to consumer tasks
-
-        /**
-         * Sets the given control bits, starting task if not running or closed.
-         * @param bits state bits, assumed to include RUN but not CLOSED
-         */
-        final void startOnSignal(int bits) {
-            if ((ctl & bits) != bits &&
-                (getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
-                tryStart();
-        }
-
-        final void onSubscribe() {
-            startOnSignal(RUN | ACTIVE);
-        }
-
-        final void onComplete() {
-            startOnSignal(RUN | ACTIVE | COMPLETE);
-        }
-
-        final void onError(Throwable ex) {
-            int c; Object[] a;      // to null out buffer on async error
-            if (ex != null)
-                pendingError = ex;  // races are OK
-            if (((c = getAndBitwiseOrCtl(ERROR | RUN | ACTIVE)) & CLOSED) == 0) {
-                if ((c & RUN) == 0)
-                    tryStart();
-                else if ((a = array) != null)
-                    Arrays.fill(a, null);
-            }
-        }
-
-        public final void cancel() {
-            onError(null);
-        }
-
-        public final void request(long n) {
-            if (n > 0L) {
-                for (;;) {
-                    long p = demand, d = p + n;  // saturate
-                    if (casDemand(p, d < p ? Long.MAX_VALUE : d))
-                        break;
-                }
-                startOnSignal(RUN | ACTIVE | REQS);
-            }
-            else
-                onError(new IllegalArgumentException(
-                            "non-positive subscription request"));
-        }
-
-        // Consumer task actions
-
-        /**
-         * Consumer loop, called from ConsumerTask, or indirectly when
-         * helping during submit.
-         */
-        final void consume() {
-            Subscriber<? super T> s;
-            if ((s = subscriber) != null) {          // hoist checks
-                subscribeOnOpen(s);
-                long d = demand;
-                for (int h = head, t = tail;;) {
-                    int c, taken; boolean empty;
-                    if (((c = ctl) & ERROR) != 0) {
-                        closeOnError(s, null);
-                        break;
-                    }
-                    else if ((taken = takeItems(s, d, h)) > 0) {
-                        head = h += taken;
-                        d = subtractDemand(taken);
-                    }
-                    else if ((d = demand) == 0L && (c & REQS) != 0)
-                        weakCasCtl(c, c & ~REQS);    // exhausted demand
-                    else if (d != 0L && (c & REQS) == 0)
-                        weakCasCtl(c, c | REQS);     // new demand
-                    else if (t == (t = tail)) {      // stability check
-                        if ((empty = (t == h)) && (c & COMPLETE) != 0) {
-                            closeOnComplete(s);      // end of stream
-                            break;
-                        }
-                        else if (empty || d == 0L) {
-                            int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
-                            if (weakCasCtl(c, c & ~bit) && bit == RUN)
-                                break;               // un-keep-alive or exit
-                        }
-                    }
-                }
-            }
-        }
-
-        /**
-         * Consumes some items until unavailable or bound or error.
-         *
-         * @param s subscriber
-         * @param d current demand
-         * @param h current head
-         * @return number taken
-         */
-        final int takeItems(Subscriber<? super T> s, long d, int h) {
-            Object[] a;
-            int k = 0, cap;
-            if ((a = array) != null && (cap = a.length) > 0) {
-                int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
-                int n = (d < (long)b) ? (int)d : b;
-                for (; k < n; ++h, ++k) {
-                    Object x = QA.getAndSet(a, h & m, null);
-                    if (waiting != 0)
-                        signalWaiter();
-                    if (x == null)
-                        break;
-                    else if (!consumeNext(s, x))
-                        break;
-                }
-            }
-            return k;
-        }
-
-        final boolean consumeNext(Subscriber<? super T> s, Object x) {
-            try {
-                @SuppressWarnings("unchecked") T y = (T) x;
-                if (s != null)
-                    s.onNext(y);
-                return true;
-            } catch (Throwable ex) {
-                handleOnNext(s, ex);
-                return false;
-            }
-        }
-
-        /**
-         * Processes exception in Subscriber.onNext.
-         */
-        final void handleOnNext(Subscriber<? super T> s, Throwable ex) {
-            BiConsumer<? super Subscriber<? super T>, ? super Throwable> h;
-            try {
-                if ((h = onNextHandler) != null)
-                    h.accept(s, ex);
-            } catch (Throwable ignore) {
-            }
-            closeOnError(s, ex);
-        }
-
-        /**
-         * Issues subscriber.onSubscribe if this is first signal.
-         */
-        final void subscribeOnOpen(Subscriber<? super T> s) {
-            if ((ctl & OPEN) == 0 && (getAndBitwiseOrCtl(OPEN) & OPEN) == 0)
-                consumeSubscribe(s);
-        }
-
-        final void consumeSubscribe(Subscriber<? super T> s) {
-            try {
-                if (s != null) // ignore if disabled
-                    s.onSubscribe(this);
-            } catch (Throwable ex) {
-                closeOnError(s, ex);
-            }
-        }
-
-        /**
-         * Issues subscriber.onComplete unless already closed.
-         */
-        final void closeOnComplete(Subscriber<? super T> s) {
-            if ((getAndBitwiseOrCtl(CLOSED) & CLOSED) == 0)
-                consumeComplete(s);
-        }
-
-        final void consumeComplete(Subscriber<? super T> s) {
-            try {
-                if (s != null)
-                    s.onComplete();
-            } catch (Throwable ignore) {
-            }
-        }
-
-        /**
-         * Issues subscriber.onError, and unblocks producer if needed.
-         */
-        final void closeOnError(Subscriber<? super T> s, Throwable ex) {
-            if ((getAndBitwiseOrCtl(ERROR | CLOSED) & CLOSED) == 0) {
-                if (ex == null)
-                    ex = pendingError;
-                pendingError = null;  // detach
-                executor = null;      // suppress racing start calls
-                signalWaiter();
-                consumeError(s, ex);
-            }
-        }
-
-        final void consumeError(Subscriber<? super T> s, Throwable ex) {
-            try {
-                if (ex != null && s != null)
-                    s.onError(ex);
-            } catch (Throwable ignore) {
-            }
-        }
-
-        // Blocking support
-
-        /**
-         * Unblocks waiting producer.
-         */
-        final void signalWaiter() {
-            Thread w;
-            waiting = 0;
-            if ((w = waiter) != null)
-                LockSupport.unpark(w);
-        }
-
-        /**
-         * Returns true if closed or space available.
-         * For ManagedBlocker.
-         */
-        public final boolean isReleasable() {
-            Object[] a; int cap;
-            return ((ctl & CLOSED) != 0 ||
-                    ((a = array) != null && (cap = a.length) > 0 &&
-                     QA.getAcquire(a, (cap - 1) & tail) == null));
-        }
-
-        /**
-         * Helps or blocks until timeout, closed, or space available.
-         */
-        final void awaitSpace(long nanos) {
-            if (!isReleasable()) {
-                ForkJoinPool.helpAsyncBlocker(executor, this);
-                if (!isReleasable()) {
-                    timeout = nanos;
-                    try {
-                        ForkJoinPool.managedBlock(this);
-                    } catch (InterruptedException ie) {
-                        timeout = INTERRUPTED;
-                    }
-                    if (timeout == INTERRUPTED)
-                        Thread.currentThread().interrupt();
-                }
-            }
-        }
-
-        /**
-         * Blocks until closed, space available or timeout.
-         * For ManagedBlocker.
-         */
-        public final boolean block() {
-            long nanos = timeout;
-            boolean timed = (nanos < Long.MAX_VALUE);
-            long deadline = timed ? System.nanoTime() + nanos : 0L;
-            while (!isReleasable()) {
-                if (Thread.interrupted()) {
-                    timeout = INTERRUPTED;
-                    if (timed)
-                        break;
-                }
-                else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
-                    break;
-                else if (waiter == null)
-                    waiter = Thread.currentThread();
-                else if (waiting == 0)
-                    waiting = 1;
-                else if (timed)
-                    LockSupport.parkNanos(this, nanos);
-                else
-                    LockSupport.park(this);
-            }
-            waiter = null;
-            waiting = 0;
-            return true;
-        }
-
-        // VarHandle mechanics
-        static final VarHandle CTL;
-        static final VarHandle DEMAND;
-        static final VarHandle QA;
-
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
-                                      int.class);
-                DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
-                                         long.class);
-                QA = MethodHandles.arrayElementVarHandle(Object[].class);
-            } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
-            }
-
-            // Reduce the risk of rare disastrous classloading in first call to
-            // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
-            Class<?> ensureLoaded = LockSupport.class;
-        }
-    }
-}
diff --git a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
index 8de28b8..9655205 100644
--- a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -36,18 +36,19 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.LockSupport;
 import java.util.concurrent.locks.ReentrantLock;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * A {@linkplain BlockingQueue blocking queue} in which each insert
  * operation must wait for a corresponding remove operation by another
@@ -76,12 +77,9 @@
  * is not guaranteed. However, a queue constructed with fairness set
  * to {@code true} grants threads access in FIFO order.
  *
- * <p>This class and its iterator implement all of the <em>optional</em>
- * methods of the {@link Collection} and {@link Iterator} interfaces.
- *
- * <p>This class is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
  *
  * @since 1.5
  * @author Doug Lea and Bill Scherer and Michael Scott
@@ -249,7 +247,7 @@
 
             boolean casNext(SNode cmp, SNode val) {
                 return cmp == next &&
-                    SNEXT.compareAndSet(this, cmp, val);
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
             }
 
             /**
@@ -262,7 +260,7 @@
              */
             boolean tryMatch(SNode s) {
                 if (match == null &&
-                    SMATCH.compareAndSet(this, null, s)) {
+                    U.compareAndSwapObject(this, MATCH, null, s)) {
                     Thread w = waiter;
                     if (w != null) {    // waiters need at most one unpark
                         waiter = null;
@@ -277,23 +275,26 @@
              * Tries to cancel a wait by matching node to itself.
              */
             void tryCancel() {
-                SMATCH.compareAndSet(this, null, this);
+                U.compareAndSwapObject(this, MATCH, null, this);
             }
 
             boolean isCancelled() {
                 return match == this;
             }
 
-            // VarHandle mechanics
-            private static final VarHandle SMATCH;
-            private static final VarHandle SNEXT;
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long MATCH;
+            private static final long NEXT;
+
             static {
                 try {
-                    MethodHandles.Lookup l = MethodHandles.lookup();
-                    SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
-                    SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
+                    MATCH = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("match"));
+                    NEXT = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("next"));
                 } catch (ReflectiveOperationException e) {
-                    throw new ExceptionInInitializerError(e);
+                    throw new Error(e);
                 }
             }
         }
@@ -303,7 +304,7 @@
 
         boolean casHead(SNode h, SNode nh) {
             return h == head &&
-                SHEAD.compareAndSet(this, h, nh);
+                U.compareAndSwapObject(this, HEAD, h, nh);
         }
 
         /**
@@ -450,10 +451,8 @@
                         continue;
                     }
                 }
-                if (spins > 0) {
-                    Thread.onSpinWait();
+                if (spins > 0)
                     spins = shouldSpin(s) ? (spins - 1) : 0;
-                }
                 else if (s.waiter == null)
                     s.waiter = w; // establish waiter so can park next iter
                 else if (!timed)
@@ -509,14 +508,15 @@
             }
         }
 
-        // VarHandle mechanics
-        private static final VarHandle SHEAD;
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
         static {
             try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
+                HEAD = U.objectFieldOffset
+                    (TransferStack.class.getDeclaredField("head"));
             } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
+                throw new Error(e);
             }
         }
     }
@@ -546,19 +546,19 @@
 
             boolean casNext(QNode cmp, QNode val) {
                 return next == cmp &&
-                    QNEXT.compareAndSet(this, cmp, val);
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
             }
 
             boolean casItem(Object cmp, Object val) {
                 return item == cmp &&
-                    QITEM.compareAndSet(this, cmp, val);
+                    U.compareAndSwapObject(this, ITEM, cmp, val);
             }
 
             /**
              * Tries to cancel by CAS'ing ref to this as item.
              */
             void tryCancel(Object cmp) {
-                QITEM.compareAndSet(this, cmp, this);
+                U.compareAndSwapObject(this, ITEM, cmp, this);
             }
 
             boolean isCancelled() {
@@ -574,16 +574,19 @@
                 return next == this;
             }
 
-            // VarHandle mechanics
-            private static final VarHandle QITEM;
-            private static final VarHandle QNEXT;
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long ITEM;
+            private static final long NEXT;
+
             static {
                 try {
-                    MethodHandles.Lookup l = MethodHandles.lookup();
-                    QITEM = l.findVarHandle(QNode.class, "item", Object.class);
-                    QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
+                    ITEM = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("item"));
+                    NEXT = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("next"));
                 } catch (ReflectiveOperationException e) {
-                    throw new ExceptionInInitializerError(e);
+                    throw new Error(e);
                 }
             }
         }
@@ -611,7 +614,7 @@
          */
         void advanceHead(QNode h, QNode nh) {
             if (h == head &&
-                QHEAD.compareAndSet(this, h, nh))
+                U.compareAndSwapObject(this, HEAD, h, nh))
                 h.next = h; // forget old next
         }
 
@@ -620,7 +623,7 @@
          */
         void advanceTail(QNode t, QNode nt) {
             if (tail == t)
-                QTAIL.compareAndSet(this, t, nt);
+                U.compareAndSwapObject(this, TAIL, t, nt);
         }
 
         /**
@@ -628,7 +631,7 @@
          */
         boolean casCleanMe(QNode cmp, QNode val) {
             return cleanMe == cmp &&
-                QCLEANME.compareAndSet(this, cmp, val);
+                U.compareAndSwapObject(this, CLEANME, cmp, val);
         }
 
         /**
@@ -749,10 +752,8 @@
                         continue;
                     }
                 }
-                if (spins > 0) {
+                if (spins > 0)
                     --spins;
-                    Thread.onSpinWait();
-                }
                 else if (s.waiter == null)
                     s.waiter = w;
                 else if (!timed)
@@ -816,21 +817,20 @@
             }
         }
 
-        // VarHandle mechanics
-        private static final VarHandle QHEAD;
-        private static final VarHandle QTAIL;
-        private static final VarHandle QCLEANME;
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
+        private static final long TAIL;
+        private static final long CLEANME;
         static {
             try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                QHEAD = l.findVarHandle(TransferQueue.class, "head",
-                                        QNode.class);
-                QTAIL = l.findVarHandle(TransferQueue.class, "tail",
-                                        QNode.class);
-                QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
-                                           QNode.class);
+                HEAD = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("head"));
+                TAIL = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("tail"));
+                CLEANME = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("cleanMe"));
             } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
+                throw new Error(e);
             }
         }
     }
@@ -1066,7 +1066,7 @@
 
     /**
      * Returns an empty spliterator in which calls to
-     * {@link Spliterator#trySplit() trySplit} always return {@code null}.
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
      *
      * @return an empty spliterator
      * @since 1.8
@@ -1112,12 +1112,15 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; (e = poll()) != null; n++)
+        for (E e; (e = poll()) != null;) {
             c.add(e);
+            ++n;
+        }
         return n;
     }
 
@@ -1128,12 +1131,15 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        Objects.requireNonNull(c);
+        if (c == null)
+            throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; n < maxElements && (e = poll()) != null; n++)
+        for (E e; n < maxElements && (e = poll()) != null;) {
             c.add(e);
+            ++n;
+        }
         return n;
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index c20d2b3..195f8ac 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -36,7 +36,6 @@
 package java.util.concurrent;
 
 import java.io.ObjectStreamField;
-import java.security.AccessControlContext;
 import java.util.Random;
 import java.util.Spliterator;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -48,8 +47,6 @@
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
 import java.util.stream.StreamSupport;
-import jdk.internal.misc.Unsafe;
-import jdk.internal.misc.VM;
 
 /**
  * A random number generator isolated to the current thread.  Like the
@@ -67,7 +64,7 @@
  * {@code ThreadLocalRandom.current().nextX(...)} (where
  * {@code X} is {@code Int}, {@code Long}, etc).
  * When all usages are of this form, it is never possible to
- * accidentally share a {@code ThreadLocalRandom} across multiple threads.
+ * accidently share a {@code ThreadLocalRandom} across multiple threads.
  *
  * <p>This class also provides additional commonly used bounded random
  * generation methods.
@@ -98,9 +95,7 @@
      * ThreadLocalRandom sequence.  The dual use is a marriage of
      * convenience, but is a simple and efficient way of reducing
      * application-level overhead and footprint of most concurrent
-     * programs. Even more opportunistically, we also define here
-     * other package-private utilities that access Thread class
-     * fields.
+     * programs.
      *
      * Even though this class subclasses java.util.Random, it uses the
      * same basic algorithm as java.util.SplittableRandom.  (See its
@@ -198,17 +193,9 @@
         return r;
     }
 
-    /**
-     * Generates a pseudorandom number with the indicated number of
-     * low-order bits.  Because this class has no subclasses, this
-     * method cannot be invoked or overridden.
-     *
-     * @param  bits random bits
-     * @return the next pseudorandom value from this random number
-     *         generator's sequence
-     */
+    // We must define this, but never use it.
     protected int next(int bits) {
-        return nextInt() >>> (32 - bits);
+        return (int)(mix64(nextSeed()) >>> (64 - bits));
     }
 
     /**
@@ -468,7 +455,7 @@
             s = v1 * v1 + v2 * v2;
         } while (s >= 1 || s == 0);
         double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
-        nextLocalGaussian.set(Double.valueOf(v2 * multiplier));
+        nextLocalGaussian.set(new Double(v2 * multiplier));
         return v1 * multiplier;
     }
 
@@ -700,7 +687,8 @@
      * @return a stream of pseudorandom {@code double} values,
      *         each with the given origin (inclusive) and bound (exclusive)
      * @throws IllegalArgumentException if {@code streamSize} is
-     *         less than zero, or {@code randomNumberOrigin}
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
      *         is greater than or equal to {@code randomNumberBound}
      * @since 1.8
      */
@@ -970,21 +958,6 @@
         return r;
     }
 
-    // Support for other package-private ThreadLocal access
-
-    /**
-     * Erases ThreadLocals by nulling out Thread maps.
-     */
-    static final void eraseThreadLocals(Thread thread) {
-        U.putObject(thread, THREADLOCALS, null);
-        U.putObject(thread, INHERITABLETHREADLOCALS, null);
-    }
-
-    static final void setInheritedAccessControlContext(Thread thread,
-                                                       AccessControlContext acc) {
-        U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
-    }
-
     // Serialization support
 
     private static final long serialVersionUID = -5851777807851030925L;
@@ -1039,10 +1012,7 @@
      */
     private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
 
-    /**
-     * The least non-zero value returned by nextDouble(). This value
-     * is scaled by a random value of 53 bits to produce a result.
-     */
+    // Constants from SplittableRandom
     private static final double DOUBLE_UNIT = 0x1.0p-53;  // 1.0  / (1L << 53)
     private static final float  FLOAT_UNIT  = 0x1.0p-24f; // 1.0f / (1 << 24)
 
@@ -1052,19 +1022,22 @@
     static final String BAD_SIZE  = "size must be non-negative";
 
     // Unsafe mechanics
-    private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long SEED = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSeed");
-    private static final long PROBE = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomProbe");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long THREADLOCALS = U.objectFieldOffset
-            (Thread.class, "threadLocals");
-    private static final long INHERITABLETHREADLOCALS = U.objectFieldOffset
-            (Thread.class, "inheritableThreadLocals");
-    private static final long INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-            (Thread.class, "inheritedAccessControlContext");
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long SEED;
+    private static final long PROBE;
+    private static final long SECONDARY;
+    static {
+        try {
+            SEED = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+            PROBE = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+            SECONDARY = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
@@ -1085,8 +1058,11 @@
 
     // at end of <clinit> to survive static initialization circularity
     static {
-        String sec = VM.getSavedProperty("java.util.secureRandomSeed");
-        if (Boolean.parseBoolean(sec)) {
+        if (java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
+                }})) {
             byte[] seedBytes = java.security.SecureRandom.getSeed(8);
             long s = (long)seedBytes[0] & 0xffL;
             for (int i = 1; i < 8; ++i)
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index f88242b..b0096a4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -79,28 +79,31 @@
  *
  * <dt>Core and maximum pool sizes</dt>
  *
- * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A {@code ThreadPoolExecutor} will automatically adjust the
  * pool size (see {@link #getPoolSize})
  * according to the bounds set by
  * corePoolSize (see {@link #getCorePoolSize}) and
  * maximumPoolSize (see {@link #getMaximumPoolSize}).
  *
  * When a new task is submitted in method {@link #execute(Runnable)},
- * if fewer than corePoolSize threads are running, a new thread is
+ * and fewer than corePoolSize threads are running, a new thread is
  * created to handle the request, even if other worker threads are
- * idle.  Else if fewer than maximumPoolSize threads are running, a
- * new thread will be created to handle the request only if the queue
- * is full.  By setting corePoolSize and maximumPoolSize the same, you
- * create a fixed-size thread pool. By setting maximumPoolSize to an
- * essentially unbounded value such as {@code Integer.MAX_VALUE}, you
- * allow the pool to accommodate an arbitrary number of concurrent
- * tasks. Most typically, core and maximum pool sizes are set only
- * upon construction, but they may also be changed dynamically using
- * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd>
+ * idle.  If there are more than corePoolSize but less than
+ * maximumPoolSize threads running, a new thread will be created only
+ * if the queue is full.  By setting corePoolSize and maximumPoolSize
+ * the same, you create a fixed-size thread pool. By setting
+ * maximumPoolSize to an essentially unbounded value such as {@code
+ * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
+ * number of concurrent tasks. Most typically, core and maximum pool
+ * sizes are set only upon construction, but they may also be changed
+ * dynamically using {@link #setCorePoolSize} and {@link
+ * #setMaximumPoolSize}. </dd>
  *
  * <dt>On-demand construction</dt>
  *
- * <dd>By default, even core threads are initially created and
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * By default, even core threads are initially created and
  * started only when new tasks arrive, but this can be overridden
  * dynamically using method {@link #prestartCoreThread} or {@link
  * #prestartAllCoreThreads}.  You probably want to prestart threads if
@@ -108,7 +111,8 @@
  *
  * <dt>Creating new threads</dt>
  *
- * <dd>New threads are created using a {@link ThreadFactory}.  If not
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New threads are created using a {@link ThreadFactory}.  If not
  * otherwise specified, a {@link Executors#defaultThreadFactory} is
  * used, that creates threads to all be in the same {@link
  * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
@@ -125,7 +129,8 @@
  *
  * <dt>Keep-alive times</dt>
  *
- * <dd>If the pool currently has more than corePoolSize threads,
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * If the pool currently has more than corePoolSize threads,
  * excess threads will be terminated if they have been idle for more
  * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
  * This provides a means of reducing resource consumption when the
@@ -142,7 +147,8 @@
  *
  * <dt>Queuing</dt>
  *
- * <dd>Any {@link BlockingQueue} may be used to transfer and hold
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Any {@link BlockingQueue} may be used to transfer and hold
  * submitted tasks.  The use of this queue interacts with pool sizing:
  *
  * <ul>
@@ -207,7 +213,8 @@
  *
  * <dt>Rejected tasks</dt>
  *
- * <dd>New tasks submitted in method {@link #execute(Runnable)} will be
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New tasks submitted in method {@link #execute(Runnable)} will be
  * <em>rejected</em> when the Executor has been shut down, and also when
  * the Executor uses finite bounds for both maximum threads and work queue
  * capacity, and is saturated.  In either case, the {@code execute} method
@@ -218,8 +225,9 @@
  *
  * <ol>
  *
- * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the handler
- * throws a runtime {@link RejectedExecutionException} upon rejection.
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * handler throws a runtime {@link RejectedExecutionException} upon
+ * rejection.
  *
  * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
  * that invokes {@code execute} itself runs the task. This provides a
@@ -243,7 +251,8 @@
  *
  * <dt>Hook methods</dt>
  *
- * <dd>This class provides {@code protected} overridable
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * This class provides {@code protected} overridable
  * {@link #beforeExecute(Thread, Runnable)} and
  * {@link #afterExecute(Runnable, Throwable)} methods that are called
  * before and after execution of each task.  These can be used to
@@ -259,19 +268,22 @@
  *
  * <dt>Queue maintenance</dt>
  *
- * <dd>Method {@link #getQueue()} allows access to the work queue
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Method {@link #getQueue()} allows access to the work queue
  * for purposes of monitoring and debugging.  Use of this method for
  * any other purpose is strongly discouraged.  Two supplied methods,
  * {@link #remove(Runnable)} and {@link #purge} are available to
  * assist in storage reclamation when large numbers of queued tasks
  * become cancelled.</dd>
  *
- * <dt>Reclamation</dt>
+ * <dt>Finalization</dt>
  *
- * <dd>A pool that is no longer referenced in a program <em>AND</em>
- * has no remaining threads may be reclaimed (garbage collected)
- * without being explicitly shutdown. You can configure a pool to
- * allow all unused threads to eventually die by setting appropriate
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads will be {@code shutdown} automatically. If
+ * you would like to ensure that unreferenced pools are reclaimed even
+ * if users forget to call {@link #shutdown}, then you must arrange
+ * that unused threads eventually die, by setting appropriate
  * keep-alive times, using a lower bound of zero core threads and/or
  * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd>
  *
@@ -362,7 +374,7 @@
      * time, but need not hit each state. The transitions are:
      *
      * RUNNING -> SHUTDOWN
-     *    On invocation of shutdown()
+     *    On invocation of shutdown(), perhaps implicitly in finalize()
      * (RUNNING or SHUTDOWN) -> STOP
      *    On invocation of shutdownNow()
      * SHUTDOWN -> TIDYING
@@ -386,7 +398,7 @@
     @ReachabilitySensitive
     private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
     private static final int COUNT_BITS = Integer.SIZE - 3;
-    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
+    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
 
     // runState is stored in the high-order bits
     private static final int RUNNING    = -1 << COUNT_BITS;
@@ -396,8 +408,8 @@
     private static final int TERMINATED =  3 << COUNT_BITS;
 
     // Packing and unpacking ctl
-    private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
-    private static int workerCountOf(int c)  { return c & COUNT_MASK; }
+    private static int runStateOf(int c)     { return c & ~CAPACITY; }
+    private static int workerCountOf(int c)  { return c & CAPACITY; }
     private static int ctlOf(int rs, int wc) { return rs | wc; }
 
     /*
@@ -437,7 +449,7 @@
      * decrements are performed within getTask.
      */
     private void decrementWorkerCount() {
-        ctl.addAndGet(-1);
+        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
     }
 
     /**
@@ -543,17 +555,12 @@
      * Core pool size is the minimum number of workers to keep alive
      * (and not allow to time out etc) unless allowCoreThreadTimeOut
      * is set, in which case the minimum is zero.
-     *
-     * Since the worker count is actually stored in COUNT_BITS bits,
-     * the effective limit is {@code corePoolSize & COUNT_MASK}.
      */
     private volatile int corePoolSize;
 
     /**
-     * Maximum pool size.
-     *
-     * Since the worker count is actually stored in COUNT_BITS bits,
-     * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
+     * Maximum pool size. Note that the actual maximum is internally
+     * bounded by CAPACITY.
      */
     private volatile int maximumPoolSize;
 
@@ -619,9 +626,6 @@
         /** Per-thread task counter */
         volatile long completedTasks;
 
-        // TODO: switch to AbstractQueuedLongSynchronizer and move
-        // completedTasks into the lock word.
-
         /**
          * Creates with given first task and thread from ThreadFactory.
          * @param firstTask the first task (null if none)
@@ -712,7 +716,7 @@
             int c = ctl.get();
             if (isRunning(c) ||
                 runStateAtLeast(c, TIDYING) ||
-                (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
+                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                 return;
             if (workerCountOf(c) != 0) { // Eligible to terminate
                 interruptIdleWorkers(ONLY_ONE);
@@ -751,12 +755,17 @@
      * specially.
      */
     private void checkShutdownAccess() {
-        // assert mainLock.isHeldByCurrentThread();
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
             security.checkPermission(shutdownPerm);
-            for (Worker w : workers)
-                security.checkAccess(w.thread);
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                for (Worker w : workers)
+                    security.checkAccess(w.thread);
+            } finally {
+                mainLock.unlock();
+            }
         }
     }
 
@@ -765,9 +774,14 @@
      * (in which case some threads may remain uninterrupted).
      */
     private void interruptWorkers() {
-        // assert mainLock.isHeldByCurrentThread();
-        for (Worker w : workers)
-            w.interruptIfStarted();
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers)
+                w.interruptIfStarted();
+        } finally {
+            mainLock.unlock();
+        }
     }
 
     /**
@@ -843,6 +857,17 @@
     }
 
     /**
+     * State check needed by ScheduledThreadPoolExecutor to
+     * enable running tasks during shutdown.
+     *
+     * @param shutdownOK true if should return true if SHUTDOWN
+     */
+    final boolean isRunningOrShutdown(boolean shutdownOK) {
+        int rs = runStateOf(ctl.get());
+        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
+    }
+
+    /**
      * Drains the task queue into a new list, normally using
      * drainTo. But if the queue is a DelayQueue or any other kind of
      * queue for which poll or drainTo may fail to remove some
@@ -893,22 +918,26 @@
      */
     private boolean addWorker(Runnable firstTask, boolean core) {
         retry:
-        for (int c = ctl.get();;) {
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
             // Check if queue empty only if necessary.
-            if (runStateAtLeast(c, SHUTDOWN)
-                && (runStateAtLeast(c, STOP)
-                    || firstTask != null
-                    || workQueue.isEmpty()))
+            if (rs >= SHUTDOWN &&
+                ! (rs == SHUTDOWN &&
+                   firstTask == null &&
+                   ! workQueue.isEmpty()))
                 return false;
 
             for (;;) {
-                if (workerCountOf(c)
-                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
+                int wc = workerCountOf(c);
+                if (wc >= CAPACITY ||
+                    wc >= (core ? corePoolSize : maximumPoolSize))
                     return false;
                 if (compareAndIncrementWorkerCount(c))
                     break retry;
                 c = ctl.get();  // Re-read ctl
-                if (runStateAtLeast(c, SHUTDOWN))
+                if (runStateOf(c) != rs)
                     continue retry;
                 // else CAS failed due to workerCount change; retry inner loop
             }
@@ -927,10 +956,10 @@
                     // Recheck while holding lock.
                     // Back out on ThreadFactory failure or if
                     // shut down before lock acquired.
-                    int c = ctl.get();
+                    int rs = runStateOf(ctl.get());
 
-                    if (isRunning(c) ||
-                        (runStateLessThan(c, STOP) && firstTask == null)) {
+                    if (rs < SHUTDOWN ||
+                        (rs == SHUTDOWN && firstTask == null)) {
                         if (t.isAlive()) // precheck that t is startable
                             throw new IllegalThreadStateException();
                         workers.add(w);
@@ -1037,10 +1066,10 @@
 
         for (;;) {
             int c = ctl.get();
+            int rs = runStateOf(c);
 
             // Check if queue empty only if necessary.
-            if (runStateAtLeast(c, SHUTDOWN)
-                && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                 decrementWorkerCount();
                 return null;
             }
@@ -1133,12 +1162,17 @@
                     wt.interrupt();
                 try {
                     beforeExecute(wt, task);
+                    Throwable thrown = null;
                     try {
                         task.run();
-                        afterExecute(task, null);
-                    } catch (Throwable ex) {
-                        afterExecute(task, ex);
-                        throw ex;
+                    } catch (RuntimeException x) {
+                        thrown = x; throw x;
+                    } catch (Error x) {
+                        thrown = x; throw x;
+                    } catch (Throwable x) {
+                        thrown = x; throw new Error(x);
+                    } finally {
+                        afterExecute(task, thrown);
                     }
                 } finally {
                     task = null;
@@ -1156,11 +1190,9 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters, the default thread factory and the default rejected
-     * execution handler.
-     *
-     * <p>It may be more convenient to use one of the {@link Executors}
-     * factory methods instead of this general purpose constructor.
+     * parameters and default thread factory and rejected execution handler.
+     * It may be more convenient to use one of the {@link Executors} factory
+     * methods instead of this general purpose constructor.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1191,8 +1223,7 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters and {@linkplain ThreadPoolExecutor.AbortPolicy
-     * default rejected execution handler}.
+     * parameters and default rejected execution handler.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1227,8 +1258,7 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters and
-     * {@linkplain Executors#defaultThreadFactory default thread factory}.
+     * parameters and default thread factory.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1316,7 +1346,7 @@
      *
      * If the task cannot be submitted for execution, either because this
      * executor has been shutdown or because its capacity has been reached,
-     * the task is handled by the current {@link RejectedExecutionHandler}.
+     * the task is handled by the current {@code RejectedExecutionHandler}.
      *
      * @param command the task to execute
      * @throws RejectedExecutionException at discretion of
@@ -1421,12 +1451,7 @@
     }
 
     public boolean isShutdown() {
-        return runStateAtLeast(ctl.get(), SHUTDOWN);
-    }
-
-    /** Used by ScheduledThreadPoolExecutor. */
-    boolean isStopped() {
-        return runStateAtLeast(ctl.get(), STOP);
+        return ! isRunning(ctl.get());
     }
 
     /**
@@ -1442,7 +1467,7 @@
      */
     public boolean isTerminating() {
         int c = ctl.get();
-        return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
+        return ! isRunning(c) && runStateLessThan(c, TERMINATED);
     }
 
     public boolean isTerminated() {
@@ -1455,7 +1480,7 @@
         final ReentrantLock mainLock = this.mainLock;
         mainLock.lock();
         try {
-            while (runStateLessThan(ctl.get(), TERMINATED)) {
+            while (!runStateAtLeast(ctl.get(), TERMINATED)) {
                 if (nanos <= 0L)
                     return false;
                 nanos = termination.awaitNanos(nanos);
@@ -1466,21 +1491,13 @@
         }
     }
 
-    // Override without "throws Throwable" for compatibility with subclasses
-    // whose finalize method invokes super.finalize() (as is recommended).
-    // Before JDK 11, finalize() had a non-empty method body.
-
-    // Android-added: The @deprecated javadoc tag
     /**
-     * @implNote Previous versions of this class had a finalize method
-     * that shut down this executor, but in this version, finalize
-     * does nothing.
-     *
-     * @deprecated Subclass is not recommended to override finalize(). If it
-     * must, please always invoke super.finalize().
+     * Invokes {@code shutdown} when this executor is no longer
+     * referenced and it has no threads.
      */
-    @Deprecated(since="9")
-    protected void finalize() {}
+    protected void finalize() {
+        shutdown();
+    }
 
     /**
      * Sets the thread factory used to create new threads.
@@ -1929,7 +1946,7 @@
         }
         int c = ctl.get();
         String runState =
-            isRunning(c) ? "Running" :
+            runStateLessThan(c, SHUTDOWN) ? "Running" :
             runStateAtLeast(c, TERMINATED) ? "Terminated" :
             "Shutting down";
         return super.toString() +
@@ -2048,10 +2065,7 @@
 
     /**
      * A handler for rejected tasks that throws a
-     * {@link RejectedExecutionException}.
-     *
-     * This is the default handler for {@link ThreadPoolExecutor} and
-     * {@link ScheduledThreadPoolExecutor}.
+     * {@code RejectedExecutionException}.
      */
     public static class AbortPolicy implements RejectedExecutionHandler {
         /**
diff --git a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
index f02aa9f..44d7964 100644
--- a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -35,8 +35,6 @@
 
 package java.util.concurrent;
 
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
 import java.util.Objects;
 
 /**
@@ -76,94 +74,137 @@
     /**
      * Time unit representing one thousandth of a microsecond.
      */
-    NANOSECONDS(TimeUnit.NANO_SCALE),
+    NANOSECONDS {
+        public long toNanos(long d)   { return d; }
+        public long toMicros(long d)  { return d/(C1/C0); }
+        public long toMillis(long d)  { return d/(C2/C0); }
+        public long toSeconds(long d) { return d/(C3/C0); }
+        public long toMinutes(long d) { return d/(C4/C0); }
+        public long toHours(long d)   { return d/(C5/C0); }
+        public long toDays(long d)    { return d/(C6/C0); }
+        public long convert(long d, TimeUnit u) { return u.toNanos(d); }
+        int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
+    },
+
     /**
      * Time unit representing one thousandth of a millisecond.
      */
-    MICROSECONDS(TimeUnit.MICRO_SCALE),
+    MICROSECONDS {
+        public long toNanos(long d)   { return x(d, C1/C0, MAX/(C1/C0)); }
+        public long toMicros(long d)  { return d; }
+        public long toMillis(long d)  { return d/(C2/C1); }
+        public long toSeconds(long d) { return d/(C3/C1); }
+        public long toMinutes(long d) { return d/(C4/C1); }
+        public long toHours(long d)   { return d/(C5/C1); }
+        public long toDays(long d)    { return d/(C6/C1); }
+        public long convert(long d, TimeUnit u) { return u.toMicros(d); }
+        int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
+    },
+
     /**
      * Time unit representing one thousandth of a second.
      */
-    MILLISECONDS(TimeUnit.MILLI_SCALE),
+    MILLISECONDS {
+        public long toNanos(long d)   { return x(d, C2/C0, MAX/(C2/C0)); }
+        public long toMicros(long d)  { return x(d, C2/C1, MAX/(C2/C1)); }
+        public long toMillis(long d)  { return d; }
+        public long toSeconds(long d) { return d/(C3/C2); }
+        public long toMinutes(long d) { return d/(C4/C2); }
+        public long toHours(long d)   { return d/(C5/C2); }
+        public long toDays(long d)    { return d/(C6/C2); }
+        public long convert(long d, TimeUnit u) { return u.toMillis(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
     /**
      * Time unit representing one second.
      */
-    SECONDS(TimeUnit.SECOND_SCALE),
+    SECONDS {
+        public long toNanos(long d)   { return x(d, C3/C0, MAX/(C3/C0)); }
+        public long toMicros(long d)  { return x(d, C3/C1, MAX/(C3/C1)); }
+        public long toMillis(long d)  { return x(d, C3/C2, MAX/(C3/C2)); }
+        public long toSeconds(long d) { return d; }
+        public long toMinutes(long d) { return d/(C4/C3); }
+        public long toHours(long d)   { return d/(C5/C3); }
+        public long toDays(long d)    { return d/(C6/C3); }
+        public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
     /**
      * Time unit representing sixty seconds.
      * @since 1.6
      */
-    MINUTES(TimeUnit.MINUTE_SCALE),
+    MINUTES {
+        public long toNanos(long d)   { return x(d, C4/C0, MAX/(C4/C0)); }
+        public long toMicros(long d)  { return x(d, C4/C1, MAX/(C4/C1)); }
+        public long toMillis(long d)  { return x(d, C4/C2, MAX/(C4/C2)); }
+        public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
+        public long toMinutes(long d) { return d; }
+        public long toHours(long d)   { return d/(C5/C4); }
+        public long toDays(long d)    { return d/(C6/C4); }
+        public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
     /**
      * Time unit representing sixty minutes.
      * @since 1.6
      */
-    HOURS(TimeUnit.HOUR_SCALE),
+    HOURS {
+        public long toNanos(long d)   { return x(d, C5/C0, MAX/(C5/C0)); }
+        public long toMicros(long d)  { return x(d, C5/C1, MAX/(C5/C1)); }
+        public long toMillis(long d)  { return x(d, C5/C2, MAX/(C5/C2)); }
+        public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
+        public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
+        public long toHours(long d)   { return d; }
+        public long toDays(long d)    { return d/(C6/C5); }
+        public long convert(long d, TimeUnit u) { return u.toHours(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
     /**
      * Time unit representing twenty four hours.
      * @since 1.6
      */
-    DAYS(TimeUnit.DAY_SCALE);
+    DAYS {
+        public long toNanos(long d)   { return x(d, C6/C0, MAX/(C6/C0)); }
+        public long toMicros(long d)  { return x(d, C6/C1, MAX/(C6/C1)); }
+        public long toMillis(long d)  { return x(d, C6/C2, MAX/(C6/C2)); }
+        public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
+        public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
+        public long toHours(long d)   { return x(d, C6/C5, MAX/(C6/C5)); }
+        public long toDays(long d)    { return d; }
+        public long convert(long d, TimeUnit u) { return u.toDays(d); }
+        int excessNanos(long d, long m) { return 0; }
+    };
 
-    // Scales as constants
-    private static final long NANO_SCALE   = 1L;
-    private static final long MICRO_SCALE  = 1000L * NANO_SCALE;
-    private static final long MILLI_SCALE  = 1000L * MICRO_SCALE;
-    private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
-    private static final long MINUTE_SCALE = 60L * SECOND_SCALE;
-    private static final long HOUR_SCALE   = 60L * MINUTE_SCALE;
-    private static final long DAY_SCALE    = 24L * HOUR_SCALE;
+    // Handy constants for conversion methods
+    static final long C0 = 1L;
+    static final long C1 = C0 * 1000L;
+    static final long C2 = C1 * 1000L;
+    static final long C3 = C2 * 1000L;
+    static final long C4 = C3 * 60L;
+    static final long C5 = C4 * 60L;
+    static final long C6 = C5 * 24L;
 
-    /*
-     * Instances cache conversion ratios and saturation cutoffs for
-     * the units up through SECONDS. Other cases compute them, in
-     * method cvt.
-     */
-
-    private final long scale;
-    private final long maxNanos;
-    private final long maxMicros;
-    private final long maxMillis;
-    private final long maxSecs;
-    private final long microRatio;
-    private final int milliRatio;   // fits in 32 bits
-    private final int secRatio;     // fits in 32 bits
-
-    private TimeUnit(long s) {
-        this.scale = s;
-        this.maxNanos = Long.MAX_VALUE / s;
-        long ur = (s >= MICRO_SCALE) ? (s / MICRO_SCALE) : (MICRO_SCALE / s);
-        this.microRatio = ur;
-        this.maxMicros = Long.MAX_VALUE / ur;
-        long mr = (s >= MILLI_SCALE) ? (s / MILLI_SCALE) : (MILLI_SCALE / s);
-        this.milliRatio = (int)mr;
-        this.maxMillis = Long.MAX_VALUE / mr;
-        long sr = (s >= SECOND_SCALE) ? (s / SECOND_SCALE) : (SECOND_SCALE / s);
-        this.secRatio = (int)sr;
-        this.maxSecs = Long.MAX_VALUE / sr;
-    }
+    static final long MAX = Long.MAX_VALUE;
 
     /**
-     * General conversion utility.
-     *
-     * @param d duration
-     * @param dst result unit scale
-     * @param src source unit scale
+     * Scale d by m, checking for overflow.
+     * This has a short name to make above code more readable.
      */
-    private static long cvt(long d, long dst, long src) {
-        long r, m;
-        if (src == dst)
-            return d;
-        else if (src < dst)
-            return d / (dst / src);
-        else if (d > (m = Long.MAX_VALUE / (r = src / dst)))
-            return Long.MAX_VALUE;
-        else if (d < -m)
-            return Long.MIN_VALUE;
-        else
-            return d * r;
+    static long x(long d, long m, long over) {
+        if (d > +over) return Long.MAX_VALUE;
+        if (d < -over) return Long.MIN_VALUE;
+        return d * m;
     }
 
+    // To maintain full signature compatibility with 1.5, and to improve the
+    // clarity of the generated javadoc (see 6287639: Abstract methods in
+    // enum classes should not be listed as abstract), method convert
+    // etc. are not declared abstract but otherwise act as abstract methods.
+
     /**
      * Converts the given time duration in the given unit to this unit.
      * Conversions from finer to coarser granularities truncate, so
@@ -179,65 +220,11 @@
      * @param sourceDuration the time duration in the given {@code sourceUnit}
      * @param sourceUnit the unit of the {@code sourceDuration} argument
      * @return the converted duration in this unit,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long convert(long sourceDuration, TimeUnit sourceUnit) {
-        switch (this) {
-        case NANOSECONDS:  return sourceUnit.toNanos(sourceDuration);
-        case MICROSECONDS: return sourceUnit.toMicros(sourceDuration);
-        case MILLISECONDS: return sourceUnit.toMillis(sourceDuration);
-        case SECONDS:      return sourceUnit.toSeconds(sourceDuration);
-        default: return cvt(sourceDuration, scale, sourceUnit.scale);
-        }
-    }
-
-    /**
-     * Converts the given time duration to this unit.
-     *
-     * <p>For any TimeUnit {@code unit},
-     * {@code unit.convert(Duration.ofNanos(n))}
-     * is equivalent to
-     * {@code unit.convert(n, NANOSECONDS)}, and
-     * {@code unit.convert(Duration.of(n, unit.toChronoUnit()))}
-     * is equivalent to {@code n} (in the absence of overflow).
-     *
-     * @apiNote
-     * This method differs from {@link Duration#toNanos()} in that it
-     * does not throw {@link ArithmeticException} on numeric overflow.
-     *
-     * @param duration the time duration
-     * @return the converted duration in this unit,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
-     * @throws NullPointerException if {@code duration} is null
-     * @see Duration#of(long,TemporalUnit)
-     * @since 11
-     */
-    public long convert(Duration duration) {
-        long secs = duration.getSeconds();
-        int nano = duration.getNano();
-        if (secs < 0 && nano > 0) {
-            // use representation compatible with integer division
-            secs++;
-            nano -= (int) SECOND_SCALE;
-        }
-        final long s, nanoVal;
-        // Optimize for the common case - NANOSECONDS without overflow
-        if (this == NANOSECONDS)
-            nanoVal = nano;
-        else if ((s = scale) < SECOND_SCALE)
-            nanoVal = nano / s;
-        else if (this == SECONDS)
-            return secs;
-        else
-            return secs / secRatio;
-        long val = secs * secRatio + nanoVal;
-        return ((secs < maxSecs && secs > -maxSecs) ||
-                (secs == maxSecs && val > 0) ||
-                (secs == -maxSecs && val < 0))
-            ? val
-            : (secs > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
+        throw new AbstractMethodError();
     }
 
     /**
@@ -245,19 +232,11 @@
      * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toNanos(long duration) {
-        long s, m;
-        if ((s = scale) == NANO_SCALE)
-            return duration;
-        else if (duration > (m = maxNanos))
-            return Long.MAX_VALUE;
-        else if (duration < -m)
-            return Long.MIN_VALUE;
-        else
-            return duration * s;
+        throw new AbstractMethodError();
     }
 
     /**
@@ -265,19 +244,11 @@
      * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toMicros(long duration) {
-        long s, m;
-        if ((s = scale) <= MICRO_SCALE)
-            return (s == MICRO_SCALE) ? duration : duration / microRatio;
-        else if (duration > (m = maxMicros))
-            return Long.MAX_VALUE;
-        else if (duration < -m)
-            return Long.MIN_VALUE;
-        else
-            return duration * microRatio;
+        throw new AbstractMethodError();
     }
 
     /**
@@ -285,19 +256,11 @@
      * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toMillis(long duration) {
-        long s, m;
-        if ((s = scale) <= MILLI_SCALE)
-            return (s == MILLI_SCALE) ? duration : duration / milliRatio;
-        else if (duration > (m = maxMillis))
-            return Long.MAX_VALUE;
-        else if (duration < -m)
-            return Long.MIN_VALUE;
-        else
-            return duration * milliRatio;
+        throw new AbstractMethodError();
     }
 
     /**
@@ -305,19 +268,11 @@
      * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toSeconds(long duration) {
-        long s, m;
-        if ((s = scale) <= SECOND_SCALE)
-            return (s == SECOND_SCALE) ? duration : duration / secRatio;
-        else if (duration > (m = maxSecs))
-            return Long.MAX_VALUE;
-        else if (duration < -m)
-            return Long.MIN_VALUE;
-        else
-            return duration * secRatio;
+        throw new AbstractMethodError();
     }
 
     /**
@@ -325,12 +280,12 @@
      * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      * @since 1.6
      */
     public long toMinutes(long duration) {
-        return cvt(duration, MINUTE_SCALE, scale);
+        throw new AbstractMethodError();
     }
 
     /**
@@ -338,12 +293,12 @@
      * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
-     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
      * @since 1.6
      */
     public long toHours(long duration) {
-        return cvt(duration, HOUR_SCALE, scale);
+        throw new AbstractMethodError();
     }
 
     /**
@@ -354,7 +309,7 @@
      * @since 1.6
      */
     public long toDays(long duration) {
-        return cvt(duration, DAY_SCALE, scale);
+        throw new AbstractMethodError();
     }
 
     /**
@@ -364,15 +319,7 @@
      * @param m the number of milliseconds
      * @return the number of nanoseconds
      */
-    private int excessNanos(long d, long m) {
-        long s;
-        if ((s = scale) == NANO_SCALE)
-            return (int)(d - (m * MILLI_SCALE));
-        else if (s == MICRO_SCALE)
-            return (int)((d * 1000L) - (m * MILLI_SCALE));
-        else
-            return 0;
-    }
+    abstract int excessNanos(long d, long m);
 
     /**
      * Performs a timed {@link Object#wait(long, int) Object.wait}
@@ -380,18 +327,16 @@
      * This is a convenience method that converts timeout arguments
      * into the form required by the {@code Object.wait} method.
      *
-     * <p>For example, you could implement a blocking {@code poll} method
-     * (see {@link BlockingQueue#poll(long, TimeUnit) BlockingQueue.poll})
+     * <p>For example, you could implement a blocking {@code poll}
+     * method (see {@link BlockingQueue#poll BlockingQueue.poll})
      * using:
      *
      * <pre> {@code
-     * public E poll(long timeout, TimeUnit unit)
+     * public synchronized Object poll(long timeout, TimeUnit unit)
      *     throws InterruptedException {
-     *   synchronized (lock) {
-     *     while (isEmpty()) {
-     *       unit.timedWait(lock, timeout);
-     *       ...
-     *     }
+     *   while (empty) {
+     *     unit.timedWait(this, timeout);
+     *     ...
      *   }
      * }}</pre>
      *
@@ -447,12 +392,14 @@
         }
     }
 
+    // BEGIN Android-removed: OpenJDK 9 ChronoUnit related code.
+    /*
     /**
      * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
      *
      * @return the converted equivalent ChronoUnit
      * @since 9
-     */
+     *
     public ChronoUnit toChronoUnit() {
         switch (this) {
         case NANOSECONDS:  return ChronoUnit.NANOS;
@@ -475,7 +422,7 @@
      *         equivalent TimeUnit
      * @throws NullPointerException if {@code chronoUnit} is null
      * @since 9
-     */
+     *
     public static TimeUnit of(ChronoUnit chronoUnit) {
         switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
         case NANOS:   return TimeUnit.NANOSECONDS;
@@ -490,5 +437,7 @@
                 "No TimeUnit equivalent for " + chronoUnit);
         }
     }
+    */
+    // END Android-removed: OpenJDK 9 ChronoUnit related code.
 
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
index 72a4108..53da597 100644
--- a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -35,6 +35,10 @@
 
 package java.util.concurrent;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * A {@link BlockingQueue} in which producers may wait for consumers
  * to receive elements.  A {@code TransferQueue} may be useful for
@@ -57,10 +61,6 @@
  * with zero capacity, such as {@link SynchronousQueue}, {@code put}
  * and {@code transfer} are effectively synonymous.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
- * Java Collections Framework</a>.
- *
  * @since 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 34a200b..447a642 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -40,13 +40,10 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.Objects;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
-import jdk.internal.misc.Unsafe;
-import jdk.internal.reflect.CallerSensitive;
-import jdk.internal.reflect.Reflection;
-import java.lang.invoke.VarHandle;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * A reflection-based utility that enables atomic updates to
@@ -62,10 +59,6 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
- * <p>Object arguments for parameters of type {@code T} that are not
- * instances of the class passed to {@link #newUpdater} will result in
- * a {@link ClassCastException} being thrown.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -114,6 +107,8 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, long expect, long update);
 
@@ -132,6 +127,8 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
 
@@ -156,8 +153,8 @@
     public abstract void lazySet(T obj, long newValue);
 
     /**
-     * Returns the current value held in the field of the given object
-     * managed by this updater.
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -279,12 +276,10 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given
-     * function, returning the previous value. The function should be
-     * side-effect-free, since it may be re-applied when attempted
-     * updates fail due to contention among threads.
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -301,12 +296,10 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given
-     * function, returning the updated value. The function should be
-     * side-effect-free, since it may be re-applied when attempted
-     * updates fail due to contention among threads.
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -323,14 +316,13 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given function
-     * to the current and given values, returning the previous value.
-     * The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among
-     * threads.  The function is applied with the current value as its
-     * first argument, and the given update as the second argument.
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -349,14 +341,13 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given function
-     * to the current and given values, returning the updated value.
-     * The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among
-     * threads.  The function is applied with the current value as its
-     * first argument, and the given update as the second argument.
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -375,7 +366,7 @@
     }
 
     private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final Unsafe U = Unsafe.getUnsafe();
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -427,17 +418,7 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            // Access to protected field members is restricted to receivers only
-            // of the accessing class, or one of its subclasses, and the
-            // accessing class must in turn be a subclass (or package sibling)
-            // of the protected member's defining class.
-            // If the updater refers to a protected field of a declaring class
-            // outside the current package, the receiver argument will be
-            // narrowed to the type of the accessing class.
-            this.cclass = (Modifier.isProtected(modifiers) &&
-                           tclass.isAssignableFrom(caller) &&
-                           !isSamePackage(tclass, caller))
-                          ? caller : tclass;
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -471,12 +452,12 @@
 
         public final boolean compareAndSet(T obj, long expect, long update) {
             accessCheck(obj);
-            return U.compareAndSetLong(obj, offset, expect, update);
+            return U.compareAndSwapLong(obj, offset, expect, update);
         }
 
         public final boolean weakCompareAndSet(T obj, long expect, long update) {
             accessCheck(obj);
-            return U.compareAndSetLong(obj, offset, expect, update);
+            return U.compareAndSwapLong(obj, offset, expect, update);
         }
 
         public final void set(T obj, long newValue) {
@@ -486,7 +467,7 @@
 
         public final void lazySet(T obj, long newValue) {
             accessCheck(obj);
-            U.putLongRelease(obj, offset, newValue);
+            U.putOrderedLong(obj, offset, newValue);
         }
 
         public final long get(T obj) {
@@ -526,7 +507,7 @@
     }
 
     private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final Unsafe U = Unsafe.getUnsafe();
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -538,8 +519,8 @@
 
         LockedUpdater(final Class<T> tclass, final String fieldName,
                       final Class<?> caller) {
-            final Field field;
-            final int modifiers;
+            Field field = null;
+            int modifiers = 0;
             try {
                 // Android-changed: Skip privilege escalation which is a noop on Android.
                 /*
@@ -578,17 +559,7 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            // Access to protected field members is restricted to receivers only
-            // of the accessing class, or one of its subclasses, and the
-            // accessing class must in turn be a subclass (or package sibling)
-            // of the protected member's defining class.
-            // If the updater refers to a protected field of a declaring class
-            // outside the current package, the receiver argument will be
-            // narrowed to the type of the accessing class.
-            this.cclass = (Modifier.isProtected(modifiers) &&
-                           tclass.isAssignableFrom(caller) &&
-                           !isSamePackage(tclass, caller))
-                          ? caller : tclass;
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -672,13 +643,4 @@
         return false;
     }
     */
-
-    /**
-     * Returns true if the two classes have the same class loader and
-     * package qualifier
-     */
-    static boolean isSamePackage(Class<?> class1, Class<?> class2) {
-        return class1.getClassLoader() == class2.getClassLoader()
-            && Objects.equals(class1.getPackageName(), class2.getPackageName());
-    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index 51ea84c..b49118b 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -35,9 +35,6 @@
 
 package java.util.concurrent.atomic;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 /**
  * An {@code AtomicMarkableReference} maintains an object reference
  * along with a mark bit, that can be updated atomically.
@@ -191,19 +188,20 @@
              casPair(current, Pair.of(expectedReference, newMark)));
     }
 
-    // VarHandle mechanics
-    private static final VarHandle PAIR;
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
-                                   Pair.class);
+            PAIR = U.objectFieldOffset
+                (AtomicMarkableReference.class.getDeclaredField("pair"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return PAIR.compareAndSet(this, cmp, val);
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 513a243..17423ad 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -40,13 +40,10 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.Objects;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
-import jdk.internal.misc.Unsafe;
-import jdk.internal.reflect.CallerSensitive;
-import jdk.internal.reflect.Reflection;
-import java.lang.invoke.VarHandle;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * A reflection-based utility that enables atomic updates to
@@ -79,10 +76,6 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
- * <p>Object arguments for parameters of type {@code T} that are not
- * instances of the class passed to {@link #newUpdater} will result in
- * a {@link ClassCastException} being thrown.
- *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -175,8 +168,8 @@
     public abstract void lazySet(T obj, V newValue);
 
     /**
-     * Returns the current value held in the field of the given object
-     * managed by this updater.
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -200,12 +193,10 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given
-     * function, returning the previous value. The function should be
-     * side-effect-free, since it may be re-applied when attempted
-     * updates fail due to contention among threads.
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -222,12 +213,10 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given
-     * function, returning the updated value. The function should be
-     * side-effect-free, since it may be re-applied when attempted
-     * updates fail due to contention among threads.
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -244,14 +233,13 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given function
-     * to the current and given values, returning the previous value.
-     * The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among
-     * threads.  The function is applied with the current value as its
-     * first argument, and the given update as the second argument.
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -270,14 +258,13 @@
     }
 
     /**
-     * Atomically updates (with memory effects as specified by {@link
-     * VarHandle#compareAndSet}) the field of the given object managed
-     * by this updater with the results of applying the given function
-     * to the current and given values, returning the updated value.
-     * The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among
-     * threads.  The function is applied with the current value as its
-     * first argument, and the given update as the second argument.
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -297,7 +284,7 @@
 
     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
         extends AtomicReferenceFieldUpdater<T,V> {
-        private static final Unsafe U = Unsafe.getUnsafe();
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -369,17 +356,7 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            // Access to protected field members is restricted to receivers only
-            // of the accessing class, or one of its subclasses, and the
-            // accessing class must in turn be a subclass (or package sibling)
-            // of the protected member's defining class.
-            // If the updater refers to a protected field of a declaring class
-            // outside the current package, the receiver argument will be
-            // narrowed to the type of the accessing class.
-            this.cclass = (Modifier.isProtected(modifiers) &&
-                           tclass.isAssignableFrom(caller) &&
-                           !isSamePackage(tclass, caller))
-                          ? caller : tclass;
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
             this.tclass = tclass;
             this.vclass = vclass;
             this.offset = U.objectFieldOffset(field);
@@ -405,15 +382,6 @@
         */
 
         /**
-         * Returns true if the two classes have the same class loader and
-         * package qualifier
-         */
-        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
-            return class1.getClassLoader() == class2.getClassLoader()
-                   && Objects.equals(class1.getPackageName(), class2.getPackageName());
-        }
-
-        /**
          * Checks that target argument is instance of cclass.  On
          * failure, throws cause.
          */
@@ -452,14 +420,14 @@
         public final boolean compareAndSet(T obj, V expect, V update) {
             accessCheck(obj);
             valueCheck(update);
-            return U.compareAndSetObject(obj, offset, expect, update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
         }
 
         public final boolean weakCompareAndSet(T obj, V expect, V update) {
             // same implementation as strong form for now
             accessCheck(obj);
             valueCheck(update);
-            return U.compareAndSetObject(obj, offset, expect, update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
         }
 
         public final void set(T obj, V newValue) {
@@ -471,7 +439,7 @@
         public final void lazySet(T obj, V newValue) {
             accessCheck(obj);
             valueCheck(newValue);
-            U.putObjectRelease(obj, offset, newValue);
+            U.putOrderedObject(obj, offset, newValue);
         }
 
         @SuppressWarnings("unchecked")
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index 47b7c7b..40ceeb2 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -35,9 +35,6 @@
 
 package java.util.concurrent.atomic;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 /**
  * An {@code AtomicStampedReference} maintains an object reference
  * along with an integer "stamp", that can be updated atomically.
@@ -191,19 +188,20 @@
              casPair(current, Pair.of(expectedReference, newStamp)));
     }
 
-    // VarHandle mechanics
-    private static final VarHandle PAIR;
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
-                                   Pair.class);
+            PAIR = U.objectFieldOffset
+                (AtomicStampedReference.class.getDeclaredField("pair"));
         } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
+            throw new Error(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return PAIR.compareAndSet(this, cmp, val);
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/package-info.java b/ojluni/src/main/java/java/util/concurrent/package-info.java
index 0e992a2..387068d 100644
--- a/ojluni/src/main/java/java/util/concurrent/package-info.java
+++ b/ojluni/src/main/java/java/util/concurrent/package-info.java
@@ -200,7 +200,7 @@
  * concurrent collection is thread-safe, but not governed by a
  * single exclusion lock.  In the particular case of
  * ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a large number of concurrent
+ * concurrent reads as well as a tunable number of concurrent
  * writes.  "Synchronized" classes can be useful when you need
  * to prevent all access to a collection via a single lock, at
  * the expense of poorer scalability.  In other cases in which
@@ -262,6 +262,7 @@
  *
  * </ul>
  *
+ *
  * The methods of all classes in {@code java.util.concurrent} and its
  * subpackages extend these guarantees to higher-level
  * synchronization.  In particular:
diff --git a/ojluni/src/test/java/io/ByteArrayInputStream/ReadAllReadNTransferTo.java b/ojluni/src/test/java/io/ByteArrayInputStream/ReadAllReadNTransferTo.java
new file mode 100644
index 0000000..c3e6e6c
--- /dev/null
+++ b/ojluni/src/test/java/io/ByteArrayInputStream/ReadAllReadNTransferTo.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.ByteArrayInputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Random;
+
+import org.testng.annotations.Test;
+
+/* @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main ReadAllReadNTransferTo
+ * @bug 8180451
+ * @summary Verify ByteArrayInputStream readAllBytes, readNBytes, and transferTo
+ * @key randomness
+ */
+public class ReadAllReadNTransferTo {
+    private static final int SIZE = 0x4d4d;
+
+    private static Random random = new Random();
+
+    @Test
+    public void testRead() throws IOException {
+        byte[] buf = new byte[SIZE];
+        random.nextBytes(buf);
+        int position = random.nextInt(SIZE/2);
+        int size = random.nextInt(SIZE - position);
+
+        ByteArrayInputStream bais =
+                new ByteArrayInputStream(buf, position, size);
+        int off = size < 2 ? 0 : random.nextInt(size / 2);
+        int len = size - off < 1 ? 0 : random.nextInt(size - off);
+
+        byte[] bN = new byte[off + len];
+        if (bais.readNBytes(bN, off, len) != len) {
+            throw new RuntimeException("readNBytes return value");
+        }
+
+        if (!Arrays.equals(Arrays.copyOfRange(bN, off, off+len),
+                Arrays.copyOfRange(buf, position, position+len))) {
+            throw new RuntimeException("readNBytes content");
+        }
+
+        byte[] bAll = bais.readAllBytes();
+        Objects.requireNonNull(bAll, "readAllBytes return value");
+        if (bAll.length != size - len) {
+            throw new RuntimeException("readAllBytes return value length");
+        }
+        if (!Arrays.equals(bAll,
+               Arrays.copyOfRange( buf, position + len, position + len + bAll.length))) {
+            throw new RuntimeException("readAllBytes content");
+        }
+
+        // XXX transferTo()
+        bais = new ByteArrayInputStream(buf);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(buf.length);
+        if (bais.transferTo(baos) != buf.length) {
+            throw new RuntimeException("transferTo return value length");
+        }
+        if (!Arrays.equals(buf, baos.toByteArray())) {
+            throw new RuntimeException("transferTo content");
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/ByteArrayOutputStream/ToString.java b/ojluni/src/test/java/io/ByteArrayOutputStream/ToString.java
new file mode 100644
index 0000000..cbd8781
--- /dev/null
+++ b/ojluni/src/test/java/io/ByteArrayOutputStream/ToString.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 1226190
+   @summary Heartbeat test of ByteArrayOutputStream's toString methods
+ */
+package test.java.io.ByteArrayOutputStream;
+
+import java.io.*;
+
+import org.testng.annotations.Test;
+
+public class ToString {
+
+    @Test
+    public void testToString() throws IOException {
+        String test = "This is a test.";
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        PrintStream p = new PrintStream(b);
+        p.print(test);
+        p.close();
+
+        if (! b.toString().equals(test))
+            throw new RuntimeException("Default encoding failed");
+        if (! b.toString("UTF8").equals(test))
+            throw new RuntimeException("UTF8 encoding failed");
+        if (! b.toString(0).equals(test))
+            throw new RuntimeException("Hibyte0 encoding failed");
+    }
+
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/ByteArrayOutputStream/Write.java b/ojluni/src/test/java/io/ByteArrayOutputStream/Write.java
new file mode 100644
index 0000000..2424263
--- /dev/null
+++ b/ojluni/src/test/java/io/ByteArrayOutputStream/Write.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4017158 8180410
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run testng Write
+ * @summary Check for correct implementation of ByteArrayInputStream.write
+ * @key randomness
+ */
+package test.java.io.ByteArrayOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class Write {
+
+    private static void doBoundsTest(byte[] b, int off, int len,
+            ByteArrayOutputStream baos)
+            throws Exception {
+        if (b != null) {
+            System.out.println("ByteArrayOutStream.write: b.length = " +
+                    b.length + " off = " + off + " len = " + len);
+        } else{
+            System.out.println("ByteArrayOutStream.write: b is null off = " +
+                    off + " len = " + len);
+        }
+
+        try {
+            baos.write(b, off, len);
+        } catch (IndexOutOfBoundsException e) {
+            System.out.println("IndexOutOfBoundsException is thrown: OKAY");
+        } catch (NullPointerException e) {
+            System.out.println("NullPointerException is thrown: OKAY");
+        } catch (Throwable e){
+            throw new RuntimeException("Unexpected Exception is thrown", e);
+        }
+
+        if (b != null) {
+            System.out.println("ByteArrayOutStream.writeBytes: b.length = " +
+                    b.length);
+        } else{
+            System.out.println("ByteArrayOutStream.writeBytes: b is null");
+        }
+
+        try {
+            baos.writeBytes(b);
+        } catch (NullPointerException e) {
+            System.out.println("NullPointerException is thrown: OKAY");
+        } catch (Throwable e){
+            throw new RuntimeException("Unexpected Exception is thrown", e);
+        }
+    }
+
+    @Test
+    public void boundsTest() throws Exception {
+        byte array1[] = {1 , 2 , 3 , 4 , 5};     // Simple array
+
+        //Create new ByteArrayOutputStream object
+        ByteArrayOutputStream y1 = new ByteArrayOutputStream(5);
+
+        doBoundsTest(array1, 0, Integer.MAX_VALUE , y1);
+        doBoundsTest(array1, 0, array1.length+100, y1);
+        doBoundsTest(array1, -1, 2, y1);
+        doBoundsTest(array1, 0, -1, y1);
+        doBoundsTest(null, 0, 2, y1);
+    }
+
+    @Test
+    public void writeTest() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Random rnd = new Random();
+        final int size = 17 + rnd.nextInt(128);
+
+        byte[] b = new byte[size];
+        rnd.nextBytes(b);
+
+        int off1 = rnd.nextInt(size / 4) + 1;
+        int len1 = Math.min(rnd.nextInt(size / 4) + 1, size - off1);
+        int off2 = rnd.nextInt(size / 2) + 1;
+        int len2 = Math.min(rnd.nextInt(size / 2) + 1, size - off2);
+
+        System.out.format("size: %d, off1: %d, len1: %d, off2: %d, len2: %d%n",
+                size, off1, len1, off2, len2);
+
+        baos.write(b, off1, len1);
+        byte[] b1 = baos.toByteArray();
+        assertEquals(b1.length, len1, "Array length test 1 failed.");
+        assertEquals(b1, Arrays.copyOfRange(b, off1, off1 + len1),
+                "Array equality test 1 failed.");
+
+        baos.write(b, off2, len2);
+        byte[] b2 = baos.toByteArray();
+        assertEquals(b2.length, len1 + len2, "Array length test 2 failed.");
+        assertEquals(Arrays.copyOfRange(b2, 0, len1),
+                Arrays.copyOfRange(b, off1, off1 + len1),
+                "Array equality test 2A failed.");
+        assertEquals(Arrays.copyOfRange(b2, len1, len1 + len2),
+                Arrays.copyOfRange(b, off2, off2 + len2),
+                "Array equality test 2B failed.");
+
+        baos.writeBytes(b);
+        byte[] b3 = baos.toByteArray();
+        int len3 = len1 + len2 + b.length;
+        if (b3.length != len1 + len2 + b.length) {
+            throw new RuntimeException("Array length test 3 failed.");
+        }
+        assertEquals(b3.length, len3, "Array length test 3 failed.");
+        assertEquals(Arrays.copyOfRange(b3, 0, len1),
+                Arrays.copyOfRange(b, off1, off1 + len1),
+                "Array equality test 3A failed.");
+        assertEquals(Arrays.copyOfRange(b3, len1, len1 + len2),
+                Arrays.copyOfRange(b, off2, off2 + len2),
+                "Array equality test 3B failed.");
+        assertEquals(Arrays.copyOfRange(b3, len1 + len2, len3), b,
+                "Array equality test 3C failed.");
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/InputStream/NullInputStream.java b/ojluni/src/test/java/io/InputStream/NullInputStream.java
new file mode 100644
index 0000000..ad281b7
--- /dev/null
+++ b/ojluni/src/test/java/io/InputStream/NullInputStream.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.InputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 4358774 8139206
+ * @run testng NullInputStream
+ * @summary Check for expected behavior of InputStream.nullInputStream().
+ */
+public class NullInputStream {
+    private static InputStream openStream;
+    private static InputStream closedStream;
+
+    @BeforeGroups(groups="open")
+    public static void openStream() {
+        openStream = InputStream.nullInputStream();
+    }
+
+    @BeforeGroups(groups="closed")
+    public static void openAndCloseStream() {
+        closedStream = InputStream.nullInputStream();
+        try {
+            closedStream.close();
+        } catch (IOException e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @AfterGroups(groups="open")
+    public static void closeStream() {
+        try {
+            openStream.close();
+        } catch (IOException e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testOpen() {
+        assertNotNull(openStream, "InputStream.nullInputStream() returned null");
+    }
+
+    @Test(groups = "open")
+    public static void testAvailable() {
+        try {
+            assertEquals(0, openStream.available(), "available() != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testRead() {
+        try {
+            assertEquals(-1, openStream.read(), "read() != -1");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testReadBII() {
+        try {
+            assertEquals(-1, openStream.read(new byte[1], 0, 1),
+                    "read(byte[],int,int) != -1");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testReadAllBytes() {
+        try {
+            assertEquals(0, openStream.readAllBytes().length,
+                    "readAllBytes().length != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testReadNBytes() {
+        try {
+            assertEquals(0, openStream.readNBytes(new byte[1], 0, 1),
+                    "readNBytes(byte[],int,int) != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testReadNBytesWithLength() {
+        try {
+            assertEquals(0, openStream.readNBytes(-1).length,
+                    "readNBytes(-1) != 0");
+            fail("Expected IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException iae) {
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+        try {
+            assertEquals(0, openStream.readNBytes(0).length,
+                    "readNBytes(0, false) != 0");
+            assertEquals(0, openStream.readNBytes(1).length,
+                    "readNBytes(1, false) != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testSkip() {
+        try {
+            assertEquals(0, openStream.skip(1), "skip() != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "open")
+    public static void testTransferTo() {
+        try {
+            assertEquals(0, openStream.transferTo(new ByteArrayOutputStream(7)),
+                    "transferTo() != 0");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testAvailableClosed() {
+        try {
+            closedStream.available();
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testReadClosed() {
+        try {
+            closedStream.read();
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testReadBIIClosed() {
+        try {
+            closedStream.read(new byte[1], 0, 1);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testReadAllBytesClosed() {
+        try {
+            closedStream.readAllBytes();
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testReadNBytesClosed() {
+        try {
+            closedStream.readNBytes(new byte[1], 0, 1);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testReadNBytesWithLengthClosed() {
+        try {
+            closedStream.readNBytes(1);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testSkipClosed() {
+        try {
+            closedStream.skip(1);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups = "closed")
+    public static void testTransferToClosed() {
+        try {
+            closedStream.transferTo(new ByteArrayOutputStream(7));
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/InputStream/ReadAllBytes.java b/ojluni/src/test/java/io/InputStream/ReadAllBytes.java
new file mode 100644
index 0000000..2851a1f
--- /dev/null
+++ b/ojluni/src/test/java/io/InputStream/ReadAllBytes.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.InputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8080835 8193832
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main ReadAllBytes
+ * @summary Basic test for InputStream.readAllBytes
+ * @key randomness
+ */
+
+public class ReadAllBytes {
+
+    private static Random generator = new Random();
+
+    @Test
+    public void testReadAllBytes() throws IOException {
+        test(new byte[]{});
+        test(new byte[]{1, 2, 3});
+        test(createRandomBytes(1024));
+        for (int shift : new int[] {13, 14, 15, 17}) {
+            for (int offset : new int[] {-1, 0, 1}) {
+                test(createRandomBytes((1 << shift) + offset));
+            }
+        }
+    }
+
+    static void test(byte[] expectedBytes) throws IOException {
+        int expectedLength = expectedBytes.length;
+        WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(expectedBytes));
+        byte[] readBytes = in.readAllBytes();
+
+        int x;
+        byte[] tmp = new byte[10];
+        check((x = in.read()) == -1,
+                "Expected end of stream from read(), got " + x);
+        check((x = in.read(tmp)) == -1,
+                "Expected end of stream from read(byte[]), got " + x);
+        check((x = in.read(tmp, 0, tmp.length)) == -1,
+                "Expected end of stream from read(byte[], int, int), got " + x);
+        check(in.readAllBytes().length == 0,
+                "Expected readAllBytes to return empty byte array");
+        check(expectedLength == readBytes.length,
+                "Expected length " + expectedLength + ", got " + readBytes.length);
+        check(Arrays.equals(expectedBytes, readBytes),
+                "Expected[" + expectedBytes + "], got:[" + readBytes + "]");
+        check(!in.isClosed(), "Stream unexpectedly closed");
+    }
+
+    static byte[] createRandomBytes(int size) {
+        byte[] bytes = new byte[size];
+        generator.nextBytes(bytes);
+        return bytes;
+    }
+
+    static void check(boolean cond, Object ... failedArgs) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : failedArgs)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+
+    static class WrapperInputStream extends FilterInputStream {
+        private boolean closed;
+        WrapperInputStream(InputStream in) { super(in); }
+        @Override public void close() throws IOException { closed = true; in.close(); }
+        boolean isClosed() { return closed; }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/InputStream/ReadNBytes.java b/ojluni/src/test/java/io/InputStream/ReadNBytes.java
new file mode 100644
index 0000000..68644ba
--- /dev/null
+++ b/ojluni/src/test/java/io/InputStream/ReadNBytes.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.InputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8080835 8139206
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main ReadNBytes
+ * @summary Basic test for InputStream.readNBytes
+ * @key randomness
+ */
+
+public class ReadNBytes {
+
+    private static Random generator = new Random();
+
+    @Test
+    public void testReadNBytes() throws IOException {
+        test(new byte[]{1, 2, 3});
+        test(createRandomBytes(1024));
+        for (int shift : new int[] {13, 15, 17}) {
+            for (int offset : new int[] {-1, 0, 1}) {
+                test(createRandomBytes((1 << shift) + offset));
+            }
+        }
+
+        test(-1);
+        test(0);
+        for (int shift : new int[] {13, 15, 17}) {
+            for (int offset : new int[] {-1, 0, 1}) {
+                test((1 << shift) + offset);
+            }
+        }
+    }
+
+    static void test(byte[] inputBytes) throws IOException {
+        int length = inputBytes.length;
+        WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(inputBytes));
+        byte[] readBytes = new byte[(length / 2) + 1];
+        int nread = in.readNBytes(readBytes, 0, readBytes.length);
+
+        int x;
+        byte[] tmp;
+        check(nread == readBytes.length,
+                "Expected number of bytes read: " + readBytes.length + ", got: " + nread);
+        check(Arrays.equals((tmp = Arrays.copyOf(inputBytes, nread)), readBytes),
+                "Expected[" + tmp + "], got:[" + readBytes + "]");
+        check(!in.isClosed(), "Stream unexpectedly closed");
+
+        // Read again
+        nread = in.readNBytes(readBytes, 0, readBytes.length);
+
+        check(nread == length - readBytes.length,
+                "Expected number of bytes read: " + (length - readBytes.length) + ", got: " + nread);
+        check(Arrays.equals((tmp = Arrays.copyOfRange(inputBytes, readBytes.length, length)),
+                Arrays.copyOf(readBytes, nread)),
+                "Expected[" + tmp + "], got:[" + readBytes + "]");
+        // Expect end of stream
+        check((x = in.read()) == -1,
+                "Expected end of stream from read(), got " + x);
+        check((x = in.read(tmp)) == -1,
+                "Expected end of stream from read(byte[]), got " + x);
+        check((x = in.read(tmp, 0, tmp.length)) == -1,
+                "Expected end of stream from read(byte[], int, int), got " + x);
+        check((x = in.readNBytes(tmp, 0, tmp.length)) == 0,
+                "Expected end of stream, 0, from readNBytes(byte[], int, int), got " + x);
+        check(!in.isClosed(), "Stream unexpectedly closed");
+    }
+
+    static void test(int max) throws IOException {
+        byte[] inputBytes = max <= 0 ? new byte[0] : createRandomBytes(max);
+        WrapperInputStream in =
+                new WrapperInputStream(new ByteArrayInputStream(inputBytes));
+
+        if (max < 0) {
+            try {
+                in.readNBytes(max);
+                check(false, "Expected IllegalArgumentException not thrown");
+            } catch (IllegalArgumentException iae) {
+                return;
+            }
+        } else if (max == 0) {
+            int x;
+            check((x = in.readNBytes(max).length) == 0,
+                    "Expected zero bytes, got " + x);
+            return;
+        }
+
+        int off = Math.toIntExact(in.skip(generator.nextInt(max/2)));
+        int len = generator.nextInt(max - 1 - off);
+        byte[] readBytes = in.readNBytes(len);
+        check(readBytes.length == len,
+                "Expected " + len + " bytes, got " + readBytes.length);
+        check(Arrays.equals(Arrays.copyOfRange(inputBytes, off, off + len), readBytes),
+                "Expected[" + Arrays.copyOfRange(inputBytes, off, off + len) +
+                        "], got:[" + readBytes + "]");
+
+        int remaining = max - (off + len);
+        readBytes = in.readNBytes(remaining);
+        check(readBytes.length == remaining,
+                "Expected " + remaining + "bytes, got " + readBytes.length);
+        check(Arrays.equals(Arrays.copyOfRange(inputBytes, off + len, max),
+                readBytes),
+                "Expected[" + Arrays.copyOfRange(inputBytes, off + len, max) +
+                        "], got:[" + readBytes + "]");
+
+        check(!in.isClosed(), "Stream unexpectedly closed");
+    }
+
+    static byte[] createRandomBytes(int size) {
+        byte[] bytes = new byte[size];
+        generator.nextBytes(bytes);
+        return bytes;
+    }
+
+    static void check(boolean cond, Object ... failedArgs) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : failedArgs)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+
+
+    static class WrapperInputStream extends FilterInputStream {
+        private boolean closed;
+        WrapperInputStream(InputStream in) { super(in); }
+        @Override public void close() throws IOException { closed = true; in.close(); }
+        boolean isClosed() { return closed; }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/InputStream/Skip.java b/ojluni/src/test/java/io/InputStream/Skip.java
new file mode 100644
index 0000000..47814d1
--- /dev/null
+++ b/ojluni/src/test/java/io/InputStream/Skip.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.InputStream;
+
+import org.testng.annotations.Test;
+
+/* @test
+   @bug 4016710
+   @summary check for correct implementation of InputStream.skip
+   */
+
+import java.io.*;
+
+
+public class Skip {
+
+    private static void dotest(InputStream in , int curpos ,
+            long total , long toskip , long expected)
+            throws Exception
+    {
+
+        try {
+
+            System.err.println("\n\nCurrently at pos = " + curpos +
+                    "\nTotal bytes in the Stream = " + total +
+                    "\nNumber of bytes to skip = " + toskip +
+                    "\nNumber of bytes that should be skipped = " +
+                    expected);
+
+            long skipped = in.skip(toskip);
+
+            System.err.println("actual number skipped: "+ skipped);
+
+            if ((skipped < 0) || (skipped > expected)) {
+                throw new RuntimeException("Unexpected number of bytes skipped");
+            }
+
+        } catch (IOException e) {
+            System.err.println("IOException is thrown - possible result");
+        } catch (Throwable e) {
+            throw new RuntimeException("Unexpected "+e+" is thrown!");
+        }
+
+    }
+
+    @Test
+    public void testSkip() throws Exception {
+
+        MyInputStream in = new MyInputStream(11);
+
+        /* test for negative skip */
+        dotest(in,  0, 11, -23,  0);
+
+        /* check for skip beyond EOF starting from before EOF */
+        dotest(in,  0, 11,  20, 11);
+
+        /* check for skip after EOF */
+        dotest(in, -1, 11,  20,  0);
+
+        in = new MyInputStream(9000);
+        /* check for skip equal to the read chunk size in InputStream.java */
+        dotest(in,  0, 9000, 2048, 2048);
+
+        /* check for skip greater than the read chunk size in InputStream.java */
+        dotest(in, 2048, 9000, 5000, 5000);
+
+        /* check for skip beyond EOF starting from before EOF */
+        dotest(in, 7048, 9000, 5000, 1952);
+
+        in = new MyInputStream(5000);
+
+        /* check for multiple chunk reads */
+        dotest(in, 0, 5000, 6000, 5000);
+
+        /*
+         * check for skip larger than Integer.MAX_VALUE
+         * (Takes about 2 hrs on a sparc ultra-1)
+         * long total = (long)Integer.MAX_VALUE + (long)10;
+         * long toskip = total - (long)6;
+         * in = new MyInputStream(total);
+         * dotest(in, 0, total, toskip, toskip);
+         */
+
+    }
+
+}
+
+class MyInputStream extends InputStream {
+
+    private int readctr = 0;
+    private long endoffile;
+
+    public MyInputStream(long endoffile) {
+        this.endoffile = endoffile;
+    }
+
+    public int read() {
+
+        if (readctr == endoffile) {
+            return -1;
+        }
+        else {
+            readctr++;
+            return 0;
+        }
+    }
+
+    public int available() { return 0; }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/InputStream/TransferTo.java b/ojluni/src/test/java/io/InputStream/TransferTo.java
new file mode 100644
index 0000000..b35bc1b
--- /dev/null
+++ b/ojluni/src/test/java/io/InputStream/TransferTo.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.InputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+
+import static java.lang.String.format;
+
+/*
+ * @test
+ * @bug 8066867
+ * @summary tests whether java.io.InputStream.transferTo conforms to its
+ *          contract defined in the javadoc
+ * @key randomness
+ */
+public class TransferTo {
+
+    @Test
+    public void ifOutIsNullThenNpeIsThrown() throws IOException {
+        try (InputStream in = input()) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        try (InputStream in = input((byte) 1)) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        try (InputStream in = input((byte) 1, (byte) 2)) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        InputStream in = null;
+        try {
+            InputStream fin = in = new ThrowingInputStream();
+            // null check should precede everything else:
+            // InputStream shouldn't be touched if OutputStream is null
+            assertThrowsNPE(() -> fin.transferTo(null), "out");
+        } finally {
+            if (in != null)
+                try {
+                    in.close();
+                } catch (IOException ignored) { }
+        }
+    }
+
+    @Test
+    public void ifExceptionInInputNeitherStreamIsClosed()
+            throws IOException {
+        transferToThenCheckIfAnyClosed(input(0, new byte[]{1, 2, 3}), output());
+        transferToThenCheckIfAnyClosed(input(1, new byte[]{1, 2, 3}), output());
+        transferToThenCheckIfAnyClosed(input(2, new byte[]{1, 2, 3}), output());
+    }
+
+    @Test
+    public void ifExceptionInOutputNeitherStreamIsClosed()
+            throws IOException {
+        transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(0));
+        transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(1));
+        transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(2));
+    }
+
+    private static void transferToThenCheckIfAnyClosed(InputStream input,
+            OutputStream output)
+            throws IOException {
+        try (CloseLoggingInputStream in = new CloseLoggingInputStream(input);
+             CloseLoggingOutputStream out =
+                     new CloseLoggingOutputStream(output)) {
+            boolean thrown = false;
+            try {
+                in.transferTo(out);
+            } catch (IOException ignored) {
+                thrown = true;
+            }
+            if (!thrown)
+                throw new AssertionError();
+
+            if (in.wasClosed() || out.wasClosed()) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void onReturnNeitherStreamIsClosed()
+            throws IOException {
+        try (CloseLoggingInputStream in =
+                     new CloseLoggingInputStream(input(new byte[]{1, 2, 3}));
+             CloseLoggingOutputStream out =
+                     new CloseLoggingOutputStream(output())) {
+
+            in.transferTo(out);
+
+            if (in.wasClosed() || out.wasClosed()) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void onReturnInputIsAtEnd() throws IOException {
+        try (InputStream in = input(new byte[]{1, 2, 3});
+             OutputStream out = output()) {
+
+            in.transferTo(out);
+
+            if (in.read() != -1) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void contents() throws IOException {
+        checkTransferredContents(new byte[0]);
+        checkTransferredContents(createRandomBytes(1024, 4096));
+        // to span through several batches
+        checkTransferredContents(createRandomBytes(16384, 16384));
+    }
+
+    private static void checkTransferredContents(byte[] bytes)
+            throws IOException {
+        try (InputStream in = input(bytes);
+             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            in.transferTo(out);
+
+            byte[] outBytes = out.toByteArray();
+            if (!Arrays.equals(bytes, outBytes)) {
+                throw new AssertionError(
+                        format("bytes.length=%s, outBytes.length=%s",
+                                bytes.length, outBytes.length));
+            }
+        }
+    }
+
+    private static byte[] createRandomBytes(int min, int maxRandomAdditive) {
+        Random rnd = new Random();
+        byte[] bytes = new byte[min + rnd.nextInt(maxRandomAdditive)];
+        rnd.nextBytes(bytes);
+        return bytes;
+    }
+
+    private static OutputStream output() {
+        return output(-1);
+    }
+
+    private static OutputStream output(int exceptionPosition) {
+        return new OutputStream() {
+
+            int pos;
+
+            @Override
+            public void write(int b) throws IOException {
+                if (pos++ == exceptionPosition)
+                    throw new IOException();
+            }
+        };
+    }
+
+    private static InputStream input(byte... bytes) {
+        return input(-1, bytes);
+    }
+
+    private static InputStream input(int exceptionPosition, byte... bytes) {
+        return new InputStream() {
+
+            int pos;
+
+            @Override
+            public int read() throws IOException {
+                if (pos == exceptionPosition) {
+                    // because of the pesky IOException swallowing in
+                    // java.io.InputStream.read(byte[], int, int)
+                    // pos++;
+                    throw new IOException();
+                }
+
+                if (pos >= bytes.length)
+                    return -1;
+                return bytes[pos++] & 0xff;
+            }
+        };
+    }
+
+    private static class ThrowingInputStream extends InputStream {
+
+        boolean closed;
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public int available() throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                throw new IOException();
+            }
+        }
+
+        @Override
+        public void reset() throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public int read() throws IOException {
+            throw new IOException();
+        }
+    }
+
+    private static class CloseLoggingInputStream extends FilterInputStream {
+
+        boolean closed;
+
+        CloseLoggingInputStream(InputStream in) {
+            super(in);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closed = true;
+            super.close();
+        }
+
+        boolean wasClosed() {
+            return closed;
+        }
+    }
+
+    private static class CloseLoggingOutputStream extends FilterOutputStream {
+
+        boolean closed;
+
+        CloseLoggingOutputStream(OutputStream out) {
+            super(out);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closed = true;
+            super.close();
+        }
+
+        boolean wasClosed() {
+            return closed;
+        }
+    }
+
+    public interface Thrower {
+        public void run() throws Throwable;
+    }
+
+    public static void assertThrowsNPE(Thrower thrower, String message) {
+        assertThrows(thrower, NullPointerException.class, message);
+    }
+
+    public static <T extends Throwable> void assertThrows(Thrower thrower,
+            Class<T> throwable,
+            String message) {
+        Throwable thrown;
+        try {
+            thrower.run();
+            thrown = null;
+        } catch (Throwable caught) {
+            thrown = caught;
+        }
+
+        if (!throwable.isInstance(thrown)) {
+            String caught = thrown == null ?
+                    "nothing" : thrown.getClass().getCanonicalName();
+            throw new AssertionError(
+                    format("Expected to catch %s, but caught %s",
+                            throwable, caught), thrown);
+        }
+
+        if (thrown != null && !message.equals(thrown.getMessage())) {
+            throw new AssertionError(
+                    format("Expected exception message to be '%s', but it's '%s'",
+                            message, thrown.getMessage()));
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/OutputStream/NullOutputStream.java b/ojluni/src/test/java/io/OutputStream/NullOutputStream.java
new file mode 100644
index 0000000..982313d
--- /dev/null
+++ b/ojluni/src/test/java/io/OutputStream/NullOutputStream.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.io.OutputStream;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 4358774
+ * @run testng NullOutputStream
+ * @summary Check for expected behavior of OutputStream.nullOutputStream().
+ */
+public class NullOutputStream {
+    private static OutputStream openStream;
+    private static OutputStream closedStream;
+
+    @BeforeGroups(groups="open")
+    public static void openStream() {
+        openStream = OutputStream.nullOutputStream();
+    }
+
+    @BeforeGroups(groups="closed")
+    public static void openAndCloseStream() {
+        closedStream = OutputStream.nullOutputStream();
+        try {
+            closedStream.close();
+        } catch (IOException e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @AfterGroups(groups="open")
+    public static void closeStream() {
+        try {
+            openStream.close();
+        } catch (IOException e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups="open")
+    public static void testOpen() {
+        assertNotNull(openStream,
+                "OutputStream.nullOutputStream() returned null");
+    }
+
+    @Test(groups="open")
+    public static void testWrite() {
+        try {
+            openStream.write(62832);
+        } catch (IOException e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups="open")
+    public static void testWriteBII() {
+        try {
+            openStream.write(new byte[] {(byte)6}, 0, 1);
+        } catch (Exception e) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    @Test(groups="closed")
+    public static void testWriteClosed() {
+        try {
+            closedStream.write(62832);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    @Test(groups="closed")
+    public static void testWriteBIIClosed() {
+        try {
+            closedStream.write(new byte[] {(byte)6}, 0, 1);
+            fail("Expected IOException not thrown");
+        } catch (IOException e) {
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
index ada751c..e97a0ab 100644
--- a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
+++ b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
@@ -170,7 +170,7 @@
         assertFalse(f.isCancelled());
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
     }
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -225,7 +225,7 @@
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
         assertTrue(f.isCancelled());
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
     }
 
     /**
@@ -372,12 +372,12 @@
 
         f = new CompletableFuture<String>();
         assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
-        assertTrue(f.toString().contains("[Completed exceptionally:"));
+        assertTrue(f.toString().contains("[Completed exceptionally]"));
 
         for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
             f = new CompletableFuture<String>();
             assertTrue(f.cancel(mayInterruptIfRunning));
-            assertTrue(f.toString().contains("[Completed exceptionally:"));
+            assertTrue(f.toString().contains("[Completed exceptionally]"));
         }
     }
 
diff --git a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
index f821a3b..575a8f3 100644
--- a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
+++ b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
@@ -590,7 +590,6 @@
                 "AtomicReferenceArray9Test",
                 "ExecutorCompletionService9Test",
                 "ForkJoinPool9Test",
-                "SubmissionPublisherTest",
             };
             addNamedTestClasses(suite, java9TestClassNames);
         }
diff --git a/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java b/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
index d0e4182..ce8baa8 100644
--- a/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
+++ b/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
@@ -856,7 +856,9 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        // Android-changed: Use a longer delay to ensure task does not expire
+        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorTest.java b/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorTest.java
index 7f85917..803adaf 100644
--- a/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorTest.java
+++ b/ojluni/src/test/java/util/concurrent/tck/ScheduledExecutorTest.java
@@ -804,7 +804,9 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        // Android-changed: Use a longer delay to ensure task does not expire
+        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
+        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java b/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
deleted file mode 100644
index bfdecbe..0000000
--- a/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
+++ /dev/null
@@ -1,1036 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Written by Doug Lea and Martin Buchholz with assistance from
- * members of JCP JSR-166 Expert Group and released to the public
- * domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package test.java.util.concurrent.tck;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Flow;
-import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.SubmissionPublisher;
-import java.util.concurrent.atomic.AtomicInteger;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import static java.util.concurrent.Flow.Subscriber;
-import static java.util.concurrent.Flow.Subscription;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-public class SubmissionPublisherTest extends JSR166TestCase {
-
-    public static void main(String[] args) {
-        main(suite(), args);
-    }
-    public static Test suite() {
-        return new TestSuite(SubmissionPublisherTest.class);
-    }
-
-    final Executor basicExecutor = basicPublisher().getExecutor();
-
-    static SubmissionPublisher<Integer> basicPublisher() {
-        return new SubmissionPublisher<Integer>();
-    }
-
-    static class SPException extends RuntimeException {}
-
-    class TestSubscriber implements Subscriber<Integer> {
-        volatile Subscription sn;
-        int last;  // Requires that onNexts are in numeric order
-        volatile int nexts;
-        volatile int errors;
-        volatile int completes;
-        volatile boolean throwOnCall = false;
-        volatile boolean request = true;
-        volatile Throwable lastError;
-
-        public synchronized void onSubscribe(Subscription s) {
-            threadAssertTrue(sn == null);
-            sn = s;
-            notifyAll();
-            if (throwOnCall)
-                throw new SPException();
-            if (request)
-                sn.request(1L);
-        }
-        public synchronized void onNext(Integer t) {
-            ++nexts;
-            notifyAll();
-            int current = t.intValue();
-            threadAssertTrue(current >= last);
-            last = current;
-            if (request)
-                sn.request(1L);
-            if (throwOnCall)
-                throw new SPException();
-        }
-        public synchronized void onError(Throwable t) {
-            threadAssertTrue(completes == 0);
-            threadAssertTrue(errors == 0);
-            lastError = t;
-            ++errors;
-            notifyAll();
-        }
-        public synchronized void onComplete() {
-            threadAssertTrue(completes == 0);
-            ++completes;
-            notifyAll();
-        }
-
-        synchronized void awaitSubscribe() {
-            while (sn == null) {
-                try {
-                    wait();
-                } catch (Exception ex) {
-                    threadUnexpectedException(ex);
-                    break;
-                }
-            }
-        }
-        synchronized void awaitNext(int n) {
-            while (nexts < n) {
-                try {
-                    wait();
-                } catch (Exception ex) {
-                    threadUnexpectedException(ex);
-                    break;
-                }
-            }
-        }
-        synchronized void awaitComplete() {
-            while (completes == 0 && errors == 0) {
-                try {
-                    wait();
-                } catch (Exception ex) {
-                    threadUnexpectedException(ex);
-                    break;
-                }
-            }
-        }
-        synchronized void awaitError() {
-            while (errors == 0) {
-                try {
-                    wait();
-                } catch (Exception ex) {
-                    threadUnexpectedException(ex);
-                    break;
-                }
-            }
-        }
-
-    }
-
-    /**
-     * A new SubmissionPublisher has no subscribers, a non-null
-     * executor, a power-of-two capacity, is not closed, and reports
-     * zero demand and lag
-     */
-    void checkInitialState(SubmissionPublisher<?> p) {
-        assertFalse(p.hasSubscribers());
-        assertEquals(0, p.getNumberOfSubscribers());
-        assertTrue(p.getSubscribers().isEmpty());
-        assertFalse(p.isClosed());
-        assertNull(p.getClosedException());
-        int n = p.getMaxBufferCapacity();
-        assertTrue((n & (n - 1)) == 0); // power of two
-        assertNotNull(p.getExecutor());
-        assertEquals(0, p.estimateMinimumDemand());
-        assertEquals(0, p.estimateMaximumLag());
-    }
-
-    /**
-     * A default-constructed SubmissionPublisher has no subscribers,
-     * is not closed, has default buffer size, and uses the
-     * defaultExecutor
-     */
-    public void testConstructor1() {
-        SubmissionPublisher<Integer> p = new SubmissionPublisher<>();
-        checkInitialState(p);
-        assertEquals(p.getMaxBufferCapacity(), Flow.defaultBufferSize());
-        Executor e = p.getExecutor(), c = ForkJoinPool.commonPool();
-        if (ForkJoinPool.getCommonPoolParallelism() > 1)
-            assertSame(e, c);
-        else
-            assertNotSame(e, c);
-    }
-
-    /**
-     * A new SubmissionPublisher has no subscribers, is not closed,
-     * has the given buffer size, and uses the given executor
-     */
-    public void testConstructor2() {
-        Executor e = Executors.newFixedThreadPool(1);
-        SubmissionPublisher<Integer> p = new SubmissionPublisher<>(e, 8);
-        checkInitialState(p);
-        assertSame(p.getExecutor(), e);
-        assertEquals(8, p.getMaxBufferCapacity());
-    }
-
-    /**
-     * A null Executor argument to SubmissionPublisher constructor
-     * throws NullPointerException
-     */
-    public void testConstructor3() {
-        try {
-            new SubmissionPublisher<Integer>(null, 8);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-    }
-
-    /**
-     * A negative capacity argument to SubmissionPublisher constructor
-     * throws IllegalArgumentException
-     */
-    public void testConstructor4() {
-        Executor e = Executors.newFixedThreadPool(1);
-        try {
-            new SubmissionPublisher<Integer>(e, -1);
-            shouldThrow();
-        } catch (IllegalArgumentException success) {}
-    }
-
-    /**
-     * A closed publisher reports isClosed with no closedException and
-     * throws IllegalStateException upon attempted submission; a
-     * subsequent close or closeExceptionally has no additional
-     * effect.
-     */
-    public void testClose() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        checkInitialState(p);
-        p.close();
-        assertTrue(p.isClosed());
-        assertNull(p.getClosedException());
-        try {
-            p.submit(1);
-            shouldThrow();
-        } catch (IllegalStateException success) {}
-        Throwable ex = new SPException();
-        p.closeExceptionally(ex);
-        assertTrue(p.isClosed());
-        assertNull(p.getClosedException());
-    }
-
-    /**
-     * A publisher closedExceptionally reports isClosed with the
-     * closedException and throws IllegalStateException upon attempted
-     * submission; a subsequent close or closeExceptionally has no
-     * additional effect.
-     */
-    public void testCloseExceptionally() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        checkInitialState(p);
-        Throwable ex = new SPException();
-        p.closeExceptionally(ex);
-        assertTrue(p.isClosed());
-        assertSame(p.getClosedException(), ex);
-        try {
-            p.submit(1);
-            shouldThrow();
-        } catch (IllegalStateException success) {}
-        p.close();
-        assertTrue(p.isClosed());
-        assertSame(p.getClosedException(), ex);
-    }
-
-    /**
-     * Upon subscription, the subscriber's onSubscribe is called, no
-     * other Subscriber methods are invoked, the publisher
-     * hasSubscribers, isSubscribed is true, and existing
-     * subscriptions are unaffected.
-     */
-    public void testSubscribe1() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        p.subscribe(s);
-        assertTrue(p.hasSubscribers());
-        assertEquals(1, p.getNumberOfSubscribers());
-        assertTrue(p.getSubscribers().contains(s));
-        assertTrue(p.isSubscribed(s));
-        s.awaitSubscribe();
-        assertNotNull(s.sn);
-        assertEquals(0, s.nexts);
-        assertEquals(0, s.errors);
-        assertEquals(0, s.completes);
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s2);
-        assertTrue(p.hasSubscribers());
-        assertEquals(2, p.getNumberOfSubscribers());
-        assertTrue(p.getSubscribers().contains(s));
-        assertTrue(p.getSubscribers().contains(s2));
-        assertTrue(p.isSubscribed(s));
-        assertTrue(p.isSubscribed(s2));
-        s2.awaitSubscribe();
-        assertNotNull(s2.sn);
-        assertEquals(0, s2.nexts);
-        assertEquals(0, s2.errors);
-        assertEquals(0, s2.completes);
-        p.close();
-    }
-
-    /**
-     * If closed, upon subscription, the subscriber's onComplete
-     * method is invoked
-     */
-    public void testSubscribe2() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        p.close();
-        p.subscribe(s);
-        s.awaitComplete();
-        assertEquals(0, s.nexts);
-        assertEquals(0, s.errors);
-        assertEquals(1, s.completes, 1);
-    }
-
-    /**
-     * If closedExceptionally, upon subscription, the subscriber's
-     * onError method is invoked
-     */
-    public void testSubscribe3() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        Throwable ex = new SPException();
-        p.closeExceptionally(ex);
-        assertTrue(p.isClosed());
-        assertSame(p.getClosedException(), ex);
-        p.subscribe(s);
-        s.awaitError();
-        assertEquals(0, s.nexts);
-        assertEquals(1, s.errors);
-    }
-
-    /**
-     * Upon attempted resubscription, the subscriber's onError is
-     * called and the subscription is cancelled.
-     */
-    public void testSubscribe4() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        p.subscribe(s);
-        assertTrue(p.hasSubscribers());
-        assertEquals(1, p.getNumberOfSubscribers());
-        assertTrue(p.getSubscribers().contains(s));
-        assertTrue(p.isSubscribed(s));
-        s.awaitSubscribe();
-        assertNotNull(s.sn);
-        assertEquals(0, s.nexts);
-        assertEquals(0, s.errors);
-        assertEquals(0, s.completes);
-        p.subscribe(s);
-        s.awaitError();
-        assertEquals(0, s.nexts);
-        assertEquals(1, s.errors);
-        assertFalse(p.isSubscribed(s));
-    }
-
-    /**
-     * An exception thrown in onSubscribe causes onError
-     */
-    public void testSubscribe5() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        s.throwOnCall = true;
-        p.subscribe(s);
-        s.awaitError();
-        assertEquals(0, s.nexts);
-        assertEquals(1, s.errors);
-        assertEquals(0, s.completes);
-    }
-
-    /**
-     * subscribe(null) throws NPE
-     */
-    public void testSubscribe6() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        try {
-            p.subscribe(null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-        checkInitialState(p);
-    }
-
-    /**
-     * Closing a publisher causes onComplete to subscribers
-     */
-    public void testCloseCompletes() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        p.submit(1);
-        p.close();
-        assertTrue(p.isClosed());
-        assertNull(p.getClosedException());
-        s1.awaitComplete();
-        assertEquals(1, s1.nexts);
-        assertEquals(1, s1.completes);
-        s2.awaitComplete();
-        assertEquals(1, s2.nexts);
-        assertEquals(1, s2.completes);
-    }
-
-    /**
-     * Closing a publisher exceptionally causes onError to subscribers
-     * after they are subscribed
-     */
-    public void testCloseExceptionallyError() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        p.submit(1);
-        p.closeExceptionally(new SPException());
-        assertTrue(p.isClosed());
-        s1.awaitSubscribe();
-        s1.awaitError();
-        assertTrue(s1.nexts <= 1);
-        assertEquals(1, s1.errors);
-        s2.awaitSubscribe();
-        s2.awaitError();
-        assertTrue(s2.nexts <= 1);
-        assertEquals(1, s2.errors);
-    }
-
-    /**
-     * Cancelling a subscription eventually causes no more onNexts to be issued
-     */
-    public void testCancel() {
-        SubmissionPublisher<Integer> p =
-            new SubmissionPublisher<>(basicExecutor, 4); // must be < 20
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s1.awaitSubscribe();
-        p.submit(1);
-        s1.sn.cancel();
-        for (int i = 2; i <= 20; ++i)
-            p.submit(i);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(20, s2.nexts);
-        assertEquals(1, s2.completes);
-        assertTrue(s1.nexts < 20);
-        assertFalse(p.isSubscribed(s1));
-    }
-
-    /**
-     * Throwing an exception in onNext causes onError
-     */
-    public void testThrowOnNext() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s1.awaitSubscribe();
-        p.submit(1);
-        s1.throwOnCall = true;
-        p.submit(2);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(2, s2.nexts);
-        s1.awaitComplete();
-        assertEquals(1, s1.errors);
-    }
-
-    /**
-     * If a handler is supplied in constructor, it is invoked when
-     * subscriber throws an exception in onNext
-     */
-    public void testThrowOnNextHandler() {
-        AtomicInteger calls = new AtomicInteger();
-        SubmissionPublisher<Integer> p = new SubmissionPublisher<>(
-            basicExecutor, 8, (s, e) -> calls.getAndIncrement());
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s1.awaitSubscribe();
-        p.submit(1);
-        s1.throwOnCall = true;
-        p.submit(2);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(2, s2.nexts);
-        assertEquals(1, s2.completes);
-        s1.awaitError();
-        assertEquals(1, s1.errors);
-        assertEquals(1, calls.get());
-    }
-
-    /**
-     * onNext items are issued in the same order to each subscriber
-     */
-    public void testOrder() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        for (int i = 1; i <= 20; ++i)
-            p.submit(i);
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertEquals(20, s2.nexts);
-        assertEquals(1, s2.completes);
-        assertEquals(20, s1.nexts);
-        assertEquals(1, s1.completes);
-    }
-
-    /**
-     * onNext is issued only if requested
-     */
-    public void testRequest1() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        p.subscribe(s1);
-        s1.awaitSubscribe();
-        assertEquals(0, p.estimateMinimumDemand());
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s2);
-        p.submit(1);
-        p.submit(2);
-        s2.awaitNext(1);
-        assertEquals(0, s1.nexts);
-        s1.sn.request(3);
-        p.submit(3);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(3, s2.nexts);
-        assertEquals(1, s2.completes);
-        s1.awaitComplete();
-        assertTrue(s1.nexts > 0);
-        assertEquals(1, s1.completes);
-    }
-
-    /**
-     * onNext is not issued when requests become zero
-     */
-    public void testRequest2() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        s1.request = false;
-        p.submit(1);
-        p.submit(2);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(2, s2.nexts);
-        assertEquals(1, s2.completes);
-        s1.awaitNext(1);
-        assertEquals(1, s1.nexts);
-    }
-
-    /**
-     * Non-positive request causes error
-     */
-    public void testRequest3() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        TestSubscriber s3 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        p.subscribe(s3);
-        s3.awaitSubscribe();
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        s1.sn.request(-1L);
-        s3.sn.request(0L);
-        p.submit(1);
-        p.submit(2);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(2, s2.nexts);
-        assertEquals(1, s2.completes);
-        s1.awaitError();
-        assertEquals(1, s1.errors);
-        assertTrue(s1.lastError instanceof IllegalArgumentException);
-        s3.awaitError();
-        assertEquals(1, s3.errors);
-        assertTrue(s3.lastError instanceof IllegalArgumentException);
-    }
-
-    /**
-     * estimateMinimumDemand reports 0 until request, nonzero after
-     * request
-     */
-    public void testEstimateMinimumDemand() {
-        TestSubscriber s = new TestSubscriber();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        s.request = false;
-        p.subscribe(s);
-        s.awaitSubscribe();
-        assertEquals(0, p.estimateMinimumDemand());
-        s.sn.request(1);
-        assertEquals(1, p.estimateMinimumDemand());
-    }
-
-    /**
-     * submit to a publisher with no subscribers returns lag 0
-     */
-    public void testEmptySubmit() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        assertEquals(0, p.submit(1));
-    }
-
-    /**
-     * submit(null) throws NPE
-     */
-    public void testNullSubmit() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        try {
-            p.submit(null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-    }
-
-    /**
-     * submit returns number of lagged items, compatible with result
-     * of estimateMaximumLag.
-     */
-    public void testLaggedSubmit() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        assertEquals(1, p.submit(1));
-        assertTrue(p.estimateMaximumLag() >= 1);
-        assertTrue(p.submit(2) >= 2);
-        assertTrue(p.estimateMaximumLag() >= 2);
-        s1.sn.request(4);
-        assertTrue(p.submit(3) >= 3);
-        assertTrue(p.estimateMaximumLag() >= 3);
-        s2.sn.request(4);
-        p.submit(4);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(4, s2.nexts);
-        s1.awaitComplete();
-        assertEquals(4, s2.nexts);
-    }
-
-    /**
-     * submit eventually issues requested items when buffer capacity is 1
-     */
-    public void testCap1Submit() {
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 1);
-        TestSubscriber s1 = new TestSubscriber();
-        TestSubscriber s2 = new TestSubscriber();
-        p.subscribe(s1);
-        p.subscribe(s2);
-        for (int i = 1; i <= 20; ++i) {
-            assertTrue(p.submit(i) >= 0);
-        }
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertEquals(20, s2.nexts);
-        assertEquals(1, s2.completes);
-        assertEquals(20, s1.nexts);
-        assertEquals(1, s1.completes);
-    }
-
-    static boolean noopHandle(AtomicInteger count) {
-        count.getAndIncrement();
-        return false;
-    }
-
-    static boolean reqHandle(AtomicInteger count, Subscriber s) {
-        count.getAndIncrement();
-        ((TestSubscriber)s).sn.request(Long.MAX_VALUE);
-        return true;
-    }
-
-    /**
-     * offer to a publisher with no subscribers returns lag 0
-     */
-    public void testEmptyOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        assertEquals(0, p.offer(1, null));
-    }
-
-    /**
-     * offer(null) throws NPE
-     */
-    public void testNullOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        try {
-            p.offer(null, null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-    }
-
-    /**
-     * offer returns number of lagged items if not saturated
-     */
-    public void testLaggedOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        assertTrue(p.offer(1, null) >= 1);
-        assertTrue(p.offer(2, null) >= 2);
-        s1.sn.request(4);
-        assertTrue(p.offer(3, null) >= 3);
-        s2.sn.request(4);
-        p.offer(4, null);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(4, s2.nexts);
-        s1.awaitComplete();
-        assertEquals(4, s2.nexts);
-    }
-
-    /**
-     * offer reports drops if saturated
-     */
-    public void testDroppedOffer() {
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        for (int i = 1; i <= 4; ++i)
-            assertTrue(p.offer(i, null) >= 0);
-        p.offer(5, null);
-        assertTrue(p.offer(6, null) < 0);
-        s1.sn.request(64);
-        assertTrue(p.offer(7, null) < 0);
-        s2.sn.request(64);
-        p.close();
-        s2.awaitComplete();
-        assertTrue(s2.nexts >= 4);
-        s1.awaitComplete();
-        assertTrue(s1.nexts >= 4);
-    }
-
-    /**
-     * offer invokes drop handler if saturated
-     */
-    public void testHandledDroppedOffer() {
-        AtomicInteger calls = new AtomicInteger();
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        for (int i = 1; i <= 4; ++i)
-            assertTrue(p.offer(i, (s, x) -> noopHandle(calls)) >= 0);
-        p.offer(4, (s, x) -> noopHandle(calls));
-        assertTrue(p.offer(6, (s, x) -> noopHandle(calls)) < 0);
-        s1.sn.request(64);
-        assertTrue(p.offer(7, (s, x) -> noopHandle(calls)) < 0);
-        s2.sn.request(64);
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertTrue(calls.get() >= 4);
-    }
-
-    /**
-     * offer succeeds if drop handler forces request
-     */
-    public void testRecoveredHandledDroppedOffer() {
-        AtomicInteger calls = new AtomicInteger();
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        int n = 0;
-        for (int i = 1; i <= 8; ++i) {
-            int d = p.offer(i, (s, x) -> reqHandle(calls, s));
-            n = n + 2 + (d < 0 ? d : 0);
-        }
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertEquals(n, s1.nexts + s2.nexts);
-        assertTrue(calls.get() >= 2);
-    }
-
-    /**
-     * Timed offer to a publisher with no subscribers returns lag 0
-     */
-    public void testEmptyTimedOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        long startTime = System.nanoTime();
-        assertEquals(0, p.offer(1, LONG_DELAY_MS, MILLISECONDS, null));
-        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
-    }
-
-    /**
-     * Timed offer with null item or TimeUnit throws NPE
-     */
-    public void testNullTimedOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        long startTime = System.nanoTime();
-        try {
-            p.offer(null, LONG_DELAY_MS, MILLISECONDS, null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-        try {
-            p.offer(1, LONG_DELAY_MS, null, null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
-    }
-
-    /**
-     * Timed offer returns number of lagged items if not saturated
-     */
-    public void testLaggedTimedOffer() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        long startTime = System.nanoTime();
-        assertTrue(p.offer(1, LONG_DELAY_MS, MILLISECONDS, null) >= 1);
-        assertTrue(p.offer(2, LONG_DELAY_MS, MILLISECONDS, null) >= 2);
-        s1.sn.request(4);
-        assertTrue(p.offer(3, LONG_DELAY_MS, MILLISECONDS, null) >= 3);
-        s2.sn.request(4);
-        p.offer(4, LONG_DELAY_MS, MILLISECONDS, null);
-        p.close();
-        s2.awaitComplete();
-        assertEquals(4, s2.nexts);
-        s1.awaitComplete();
-        assertEquals(4, s2.nexts);
-        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
-    }
-
-    /**
-     * Timed offer reports drops if saturated
-     */
-    public void testDroppedTimedOffer() {
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        long delay = timeoutMillis();
-        for (int i = 1; i <= 4; ++i)
-            assertTrue(p.offer(i, delay, MILLISECONDS, null) >= 0);
-        long startTime = System.nanoTime();
-        assertTrue(p.offer(5, delay, MILLISECONDS, null) < 0);
-        s1.sn.request(64);
-        assertTrue(p.offer(6, delay, MILLISECONDS, null) < 0);
-        // 2 * delay should elapse but check only 1 * delay to allow timer slop
-        assertTrue(millisElapsedSince(startTime) >= delay);
-        s2.sn.request(64);
-        p.close();
-        s2.awaitComplete();
-        assertTrue(s2.nexts >= 2);
-        s1.awaitComplete();
-        assertTrue(s1.nexts >= 2);
-    }
-
-    /**
-     * Timed offer invokes drop handler if saturated
-     */
-    public void testHandledDroppedTimedOffer() {
-        AtomicInteger calls = new AtomicInteger();
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        long delay = timeoutMillis();
-        for (int i = 1; i <= 4; ++i)
-            assertTrue(p.offer(i, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) >= 0);
-        long startTime = System.nanoTime();
-        assertTrue(p.offer(5, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
-        s1.sn.request(64);
-        assertTrue(p.offer(6, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
-        assertTrue(millisElapsedSince(startTime) >= delay);
-        s2.sn.request(64);
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertTrue(calls.get() >= 2);
-    }
-
-    /**
-     * Timed offer succeeds if drop handler forces request
-     */
-    public void testRecoveredHandledDroppedTimedOffer() {
-        AtomicInteger calls = new AtomicInteger();
-        SubmissionPublisher<Integer> p
-            = new SubmissionPublisher<>(basicExecutor, 4);
-        TestSubscriber s1 = new TestSubscriber();
-        s1.request = false;
-        TestSubscriber s2 = new TestSubscriber();
-        s2.request = false;
-        p.subscribe(s1);
-        p.subscribe(s2);
-        s2.awaitSubscribe();
-        s1.awaitSubscribe();
-        int n = 0;
-        long delay = timeoutMillis();
-        long startTime = System.nanoTime();
-        for (int i = 1; i <= 6; ++i) {
-            int d = p.offer(i, delay, MILLISECONDS, (s, x) -> reqHandle(calls, s));
-            n = n + 2 + (d < 0 ? d : 0);
-        }
-        assertTrue(millisElapsedSince(startTime) >= delay);
-        p.close();
-        s2.awaitComplete();
-        s1.awaitComplete();
-        assertEquals(n, s1.nexts + s2.nexts);
-        assertTrue(calls.get() >= 2);
-    }
-
-    /**
-     * consume returns a CompletableFuture that is done when
-     * publisher completes
-     */
-    public void testConsume() {
-        AtomicInteger sum = new AtomicInteger();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        CompletableFuture<Void> f =
-            p.consume((Integer x) -> sum.getAndAdd(x.intValue()));
-        int n = 20;
-        for (int i = 1; i <= n; ++i)
-            p.submit(i);
-        p.close();
-        f.join();
-        assertEquals((n * (n + 1)) / 2, sum.get());
-    }
-
-    /**
-     * consume(null) throws NPE
-     */
-    public void testConsumeNPE() {
-        SubmissionPublisher<Integer> p = basicPublisher();
-        try {
-            CompletableFuture<Void> f = p.consume(null);
-            shouldThrow();
-        } catch (NullPointerException success) {}
-    }
-
-    /**
-     * consume eventually stops processing published items if cancelled
-     */
-    public void testCancelledConsume() {
-        AtomicInteger count = new AtomicInteger();
-        SubmissionPublisher<Integer> p = basicPublisher();
-        CompletableFuture<Void> f = p.consume(x -> count.getAndIncrement());
-        f.cancel(true);
-        int n = 1000000; // arbitrary limit
-        for (int i = 1; i <= n; ++i)
-            p.submit(i);
-        assertTrue(count.get() < n);
-    }
-
-    /**
-     * Tests scenario for
-     * JDK-8187947: A race condition in SubmissionPublisher
-     * cvs update -D '2017-11-25' src/main/java/util/concurrent/SubmissionPublisher.java && ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=SubmissionPublisherTest -Djsr166.methodFilter=testMissedSignal tck; cvs update -A src/main/java/util/concurrent/SubmissionPublisher.java
-     */
-    public void testMissedSignal_8187947() throws Exception {
-        if (!atLeastJava9()) return; // backport to jdk8 too hard
-        final int N = expensiveTests ? (1 << 20) : (1 << 10);
-        final CountDownLatch finished = new CountDownLatch(1);
-        final SubmissionPublisher<Boolean> pub = new SubmissionPublisher<>();
-        class Sub implements Subscriber<Boolean> {
-            int received;
-            public void onSubscribe(Subscription s) {
-                s.request(N);
-            }
-            public void onNext(Boolean item) {
-                if (++received == N)
-                    finished.countDown();
-                else
-                    CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
-            }
-            public void onError(Throwable t) { throw new AssertionError(t); }
-            public void onComplete() {}
-        }
-        pub.subscribe(new Sub());
-        CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
-        await(finished);
-    }
-}
diff --git a/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java b/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
deleted file mode 100644
index 5cddf1c..0000000
--- a/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Written by Doug Lea and Martin Buchholz with assistance from
- * members of JCP JSR-166 Expert Group and released to the public
- * domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package test.java.util.concurrent.tck;
-import static java.util.concurrent.TimeUnit.DAYS;
-import static java.util.concurrent.TimeUnit.HOURS;
-import static java.util.concurrent.TimeUnit.MICROSECONDS;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.MINUTES;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.LongStream;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class TimeUnit8Test extends JSR166TestCase {
-    public static void main(String[] args) {
-        main(suite(), args);
-    }
-
-    public static Test suite() {
-        return new TestSuite(TimeUnit8Test.class);
-    }
-
-    /**
-     * tests for toChronoUnit.
-     */
-    public void testToChronoUnit() throws Exception {
-        assertSame(ChronoUnit.NANOS,   NANOSECONDS.toChronoUnit());
-        assertSame(ChronoUnit.MICROS,  MICROSECONDS.toChronoUnit());
-        assertSame(ChronoUnit.MILLIS,  MILLISECONDS.toChronoUnit());
-        assertSame(ChronoUnit.SECONDS, SECONDS.toChronoUnit());
-        assertSame(ChronoUnit.MINUTES, MINUTES.toChronoUnit());
-        assertSame(ChronoUnit.HOURS,   HOURS.toChronoUnit());
-        assertSame(ChronoUnit.DAYS,    DAYS.toChronoUnit());
-
-        // Every TimeUnit has a defined ChronoUnit equivalent
-        for (TimeUnit x : TimeUnit.values())
-            assertSame(x, TimeUnit.of(x.toChronoUnit()));
-    }
-
-    /**
-     * tests for TimeUnit.of(ChronoUnit).
-     */
-    public void testTimeUnitOf() throws Exception {
-        assertSame(NANOSECONDS,  TimeUnit.of(ChronoUnit.NANOS));
-        assertSame(MICROSECONDS, TimeUnit.of(ChronoUnit.MICROS));
-        assertSame(MILLISECONDS, TimeUnit.of(ChronoUnit.MILLIS));
-        assertSame(SECONDS,      TimeUnit.of(ChronoUnit.SECONDS));
-        assertSame(MINUTES,      TimeUnit.of(ChronoUnit.MINUTES));
-        assertSame(HOURS,        TimeUnit.of(ChronoUnit.HOURS));
-        assertSame(DAYS,         TimeUnit.of(ChronoUnit.DAYS));
-
-        assertThrows(NullPointerException.class,
-                     () -> TimeUnit.of((ChronoUnit)null));
-
-        // ChronoUnits either round trip to their TimeUnit
-        // equivalents, or throw IllegalArgumentException.
-        for (ChronoUnit cu : ChronoUnit.values()) {
-            final TimeUnit tu;
-            try {
-                tu = TimeUnit.of(cu);
-            } catch (IllegalArgumentException acceptable) {
-                continue;
-            }
-            assertSame(cu, tu.toChronoUnit());
-        }
-    }
-
-    /**
-     * convert(Duration) roundtrips with Duration.ofXXXX and Duration.of(long, ChronoUnit)
-     */
-    public void testConvertDuration_roundtripDurationOf() {
-        long n = ThreadLocalRandom.current().nextLong();
-
-        assertEquals(n, NANOSECONDS.convert(Duration.ofNanos(n)));
-        assertEquals(n, NANOSECONDS.convert(Duration.of(n, ChronoUnit.NANOS)));
-        assertEquals(n, MILLISECONDS.convert(Duration.ofMillis(n)));
-        assertEquals(n, MILLISECONDS.convert(Duration.of(n, ChronoUnit.MILLIS)));
-        assertEquals(n, SECONDS.convert(Duration.ofSeconds(n)));
-        assertEquals(n, SECONDS.convert(Duration.of(n, ChronoUnit.SECONDS)));
-        n /= 60;
-        assertEquals(n, MINUTES.convert(Duration.ofMinutes(n)));
-        assertEquals(n, MINUTES.convert(Duration.of(n, ChronoUnit.MINUTES)));
-        n /= 60;
-        assertEquals(n, HOURS.convert(Duration.ofHours(n)));
-        assertEquals(n, HOURS.convert(Duration.of(n, ChronoUnit.HOURS)));
-        n /= 24;
-        assertEquals(n, DAYS.convert(Duration.ofDays(n)));
-        assertEquals(n, DAYS.convert(Duration.of(n, ChronoUnit.DAYS)));
-    }
-
-    /**
-     * convert(Duration.ofNanos(n)) agrees with convert(n, NANOSECONDS)
-     */
-    public void testConvertDuration_roundtripDurationOfNanos() {
-        // Test values near unit transitions and near overflow.
-        LongStream.concat(
-                Arrays.stream(TimeUnit.values()).mapToLong(u -> u.toNanos(1)),
-                LongStream.of(Long.MAX_VALUE, Long.MIN_VALUE))
-            .flatMap(n -> LongStream.of(n, n + 1, n - 1))
-            .flatMap(n -> LongStream.of(n, n + 1_000_000_000, n - 1_000_000_000))
-            .flatMap(n -> LongStream.of(n, -n))
-            // .peek(System.err::println)
-            .forEach(n -> Arrays.stream(TimeUnit.values()).forEach(
-                u -> assertEquals(u.convert(n, NANOSECONDS),
-                                  u.convert(Duration.ofNanos(n)))));
-    }
-
-    /**
-     * convert(Duration) doesn't misbehave near Long.MAX_VALUE and Long.MIN_VALUE.
-     */
-    public void testConvertDuration_nearOverflow() {
-        ChronoUnit NANOS = ChronoUnit.NANOS;
-        Duration maxDuration = Duration.ofSeconds(Long.MAX_VALUE, 999_999_999);
-        Duration minDuration = Duration.ofSeconds(Long.MIN_VALUE, 0);
-
-        for (TimeUnit u : TimeUnit.values()) {
-            ChronoUnit cu = u.toChronoUnit();
-            long r;
-            if (u.toNanos(1) > SECONDS.toNanos(1)) {
-                r = u.toNanos(1) / SECONDS.toNanos(1);
-
-                assertThrows(ArithmeticException.class,
-                             () -> Duration.of(Long.MAX_VALUE, cu),
-                             () -> Duration.of(Long.MIN_VALUE, cu));
-            } else {
-                r = 1;
-
-                Duration max = Duration.of(Long.MAX_VALUE, cu);
-                Duration min = Duration.of(Long.MIN_VALUE, cu);
-                assertEquals(Long.MAX_VALUE, u.convert(max));
-                assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, NANOS)));
-                assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, cu)));
-                assertEquals(Long.MIN_VALUE, u.convert(min));
-                assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, NANOS)));
-                assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, cu)));
-                assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, NANOS)));
-                if (u != SECONDS) {
-                    assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, cu)));
-                    assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, NANOS)));
-                    assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, cu)));
-                }
-            }
-
-            assertEquals(Long.MAX_VALUE / r, u.convert(maxDuration));
-            assertEquals(Long.MIN_VALUE / r, u.convert(minDuration));
-        }
-    }
-
-}
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index b13a5db..8eff1b3 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -980,7 +980,6 @@
         "ojluni/src/main/java/java/util/concurrent/ScheduledFuture.java",
         "ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java",
         "ojluni/src/main/java/java/util/concurrent/Semaphore.java",
-        "ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java",
         "ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java",
         "ojluni/src/main/java/java/util/concurrent/ThreadFactory.java",
         "ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java",