Merge "Revert "JSR-166 update""
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 756ec02..21ad635 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -215,7 +215,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under, jsr166-tests)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs core-junit
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := jsr166-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
index c293f13..9e83de2 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
@@ -18,7 +18,6 @@
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -39,7 +38,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AbstractExecutorServiceTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -197,25 +196,28 @@
public void testInterruptedSubmit() throws InterruptedException {
final CountDownLatch submitted = new CountDownLatch(1);
final CountDownLatch quittingTime = new CountDownLatch(1);
- final Callable<Void> awaiter = new CheckedCallable<Void>() {
- public Void realCall() throws InterruptedException {
- assertTrue(quittingTime.await(2*LONG_DELAY_MS, MILLISECONDS));
- return null;
- }};
final ExecutorService p
= new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, quittingTime)) {
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ final Callable<Void> awaiter = new CheckedCallable<Void>() {
+ public Void realCall() throws InterruptedException {
+ quittingTime.await();
+ return null;
+ }};
+ try {
+ Thread t = new Thread(new CheckedInterruptedRunnable() {
public void realRun() throws Exception {
Future<Void> future = p.submit(awaiter);
submitted.countDown();
future.get();
}});
-
- await(submitted);
+ t.start();
+ submitted.await();
t.interrupt();
- awaitTermination(t);
+ t.join();
+ } finally {
+ quittingTime.countDown();
+ joinPool(p);
}
}
@@ -224,32 +226,34 @@
* throws exception
*/
public void testSubmitEE() throws InterruptedException {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- Callable c = new Callable() {
- public Object call() { throw new ArithmeticException(); }};
- try {
- p.submit(c).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof ArithmeticException);
- }
+
+ Callable c = new Callable() {
+ public Object call() { throw new ArithmeticException(); }};
+
+ try {
+ p.submit(c).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof ArithmeticException);
}
+ joinPool(p);
}
/**
* invokeAny(null) throws NPE
*/
public void testInvokeAny1() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -257,12 +261,13 @@
* invokeAny(empty collection) throws IAE
*/
public void testInvokeAny2() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -270,16 +275,17 @@
* invokeAny(c) throws NPE if c has null elements
*/
public void testInvokeAny3() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<Long>> l = new ArrayList<Callable<Long>>();
- l.add(new Callable<Long>() {
- public Long call() { throw new ArithmeticException(); }});
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<Long>> l = new ArrayList<Callable<Long>>();
+ l.add(new Callable<Long>() {
+ public Long call() { throw new ArithmeticException(); }});
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -287,16 +293,16 @@
* invokeAny(c) throws ExecutionException if no task in c completes
*/
public void testInvokeAny4() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -304,13 +310,15 @@
* invokeAny(c) returns result of some task in c if at least one completes
*/
public void testInvokeAny5() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -318,12 +326,13 @@
* invokeAll(null) throws NPE
*/
public void testInvokeAll1() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -331,10 +340,12 @@
* invokeAll(empty collection) returns empty collection
*/
public void testInvokeAll2() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -342,15 +353,16 @@
* invokeAll(c) throws NPE if c has null elements
*/
public void testInvokeAll3() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -358,8 +370,8 @@
* get of returned element of invokeAll(c) throws exception on failed task
*/
public void testInvokeAll4() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new NPETask());
List<Future<String>> futures = e.invokeAll(l);
@@ -370,6 +382,8 @@
} catch (ExecutionException success) {
assertTrue(success.getCause() instanceof NullPointerException);
}
+ } finally {
+ joinPool(e);
}
}
@@ -377,8 +391,8 @@
* invokeAll(c) returns results of all completed tasks in c
*/
public void testInvokeAll5() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -386,6 +400,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -393,12 +409,13 @@
* timed invokeAny(null) throws NPE
*/
public void testTimedInvokeAny1() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -406,14 +423,15 @@
* timed invokeAny(null time unit) throws NPE
*/
public void testTimedInvokeAnyNullTimeUnit() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -421,13 +439,13 @@
* timed invokeAny(empty collection) throws IAE
*/
public void testTimedInvokeAny2() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -435,16 +453,17 @@
* timed invokeAny(c) throws NPE if c has null elements
*/
public void testTimedInvokeAny3() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<Long>> l = new ArrayList<Callable<Long>>();
- l.add(new Callable<Long>() {
- public Long call() { throw new ArithmeticException(); }});
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<Long>> l = new ArrayList<Callable<Long>>();
+ l.add(new Callable<Long>() {
+ public Long call() { throw new ArithmeticException(); }});
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -452,18 +471,16 @@
* timed invokeAny(c) throws ExecutionException if no task completes
*/
public void testTimedInvokeAny4() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -471,15 +488,15 @@
* timed invokeAny(c) returns result of some task in c
*/
public void testTimedInvokeAny5() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -487,12 +504,13 @@
* timed invokeAll(null) throws NPE
*/
public void testTimedInvokeAll1() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -500,14 +518,15 @@
* timed invokeAll(null time unit) throws NPE
*/
public void testTimedInvokeAllNullTimeUnit() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -515,10 +534,12 @@
* timed invokeAll(empty collection) returns empty collection
*/
public void testTimedInvokeAll2() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -526,15 +547,16 @@
* timed invokeAll(c) throws NPE if c has null elements
*/
public void testTimedInvokeAll3() throws InterruptedException {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -542,12 +564,12 @@
* get of returned element of invokeAll(c) throws exception on failed task
*/
public void testTimedInvokeAll4() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new NPETask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(1, futures.size());
try {
futures.get(0).get();
@@ -555,6 +577,8 @@
} catch (ExecutionException success) {
assertTrue(success.getCause() instanceof NullPointerException);
}
+ } finally {
+ joinPool(e);
}
}
@@ -562,51 +586,41 @@
* timed invokeAll(c) returns results of all completed tasks in c
*/
public void testTimedInvokeAll5() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new DirectExecutorService();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
/**
* timed invokeAll cancels tasks not completed by timeout
*/
- public void testTimedInvokeAll6() throws Exception {
- final ExecutorService e = new DirectExecutorService();
- try (PoolCleaner cleaner = cleaner(e)) {
- for (long timeout = timeoutMillis();;) {
- List<Callable<String>> tasks = new ArrayList<>();
- tasks.add(new StringTask("0"));
- tasks.add(Executors.callable(possiblyInterruptedRunnable(timeout),
- TEST_STRING));
- tasks.add(new StringTask("2"));
- long startTime = System.nanoTime();
- List<Future<String>> futures =
- e.invokeAll(tasks, timeout, MILLISECONDS);
- assertEquals(tasks.size(), futures.size());
- assertTrue(millisElapsedSince(startTime) >= timeout);
- for (Future future : futures)
- assertTrue(future.isDone());
- try {
- assertEquals("0", futures.get(0).get());
- assertEquals(TEST_STRING, futures.get(1).get());
- } catch (CancellationException retryWithLongerTimeout) {
- // unusual delay before starting second task
- timeout *= 2;
- if (timeout >= LONG_DELAY_MS / 2)
- fail("expected exactly one task to be cancelled");
- continue;
- }
- assertTrue(futures.get(2).isCancelled());
- break;
- }
+ public void testTimedInvokeAll6() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(possiblyInterruptedRunnable(2 * SHORT_DELAY_MS), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertFalse(futures.get(1).isCancelled());
+ assertTrue(futures.get(2).isCancelled());
+ } finally {
+ joinPool(e);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
index bf25668..2aa7326 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
@@ -24,7 +24,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AbstractQueueTest.class);
+ // return new TestSuite(...);
// }
static class Succeed extends AbstractQueue<Integer> {
@@ -158,7 +158,7 @@
public void testAddAll3() {
Succeed q = new Succeed();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
try {
q.addAll(Arrays.asList(ints));
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
index c462c73..8604d86 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AbstractQueuedLongSynchronizerTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -241,33 +241,25 @@
*/
void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) {
long timeoutMillis = timeoutMillis();
- long startTime;
+ long startTime = System.nanoTime();
try {
switch (awaitMethod) {
case awaitTimed:
- startTime = System.nanoTime();
assertFalse(c.await(timeoutMillis, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitNanos:
- startTime = System.nanoTime();
long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
long nanosRemaining = c.awaitNanos(nanosTimeout);
assertTrue(nanosRemaining <= 0);
- assertTrue(nanosRemaining > -MILLISECONDS.toNanos(LONG_DELAY_MS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitUntil:
- // We shouldn't assume that nanoTime and currentTimeMillis
- // use the same time source, so don't use nanoTime here.
- java.util.Date delayedDate = delayedDate(timeoutMillis());
assertFalse(c.awaitUntil(delayedDate(timeoutMillis)));
- assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
break;
default:
throw new UnsupportedOperationException();
}
} catch (InterruptedException ie) { threadUnexpectedException(ie); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
index d102fc6..b3c4110 100644
--- a/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AbstractQueuedSynchronizerTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -244,33 +244,25 @@
*/
void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) {
long timeoutMillis = timeoutMillis();
- long startTime;
+ long startTime = System.nanoTime();
try {
switch (awaitMethod) {
case awaitTimed:
- startTime = System.nanoTime();
assertFalse(c.await(timeoutMillis, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitNanos:
- startTime = System.nanoTime();
long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
long nanosRemaining = c.awaitNanos(nanosTimeout);
assertTrue(nanosRemaining <= 0);
- assertTrue(nanosRemaining > -MILLISECONDS.toNanos(LONG_DELAY_MS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitUntil:
- // We shouldn't assume that nanoTime and currentTimeMillis
- // use the same time source, so don't use nanoTime here.
- java.util.Date delayedDate = delayedDate(timeoutMillis());
assertFalse(c.awaitUntil(delayedDate(timeoutMillis)));
- assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
break;
default:
throw new UnsupportedOperationException();
}
} catch (InterruptedException ie) { threadUnexpectedException(ie); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
index 902ae40..247c90e 100644
--- a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
@@ -26,7 +26,7 @@
public class ArrayBlockingQueueTest extends JSR166TestCase {
- // android-note: These tests have been moved into their own separate
+ // android-note: These tests have been moved into their own separate
// classes to work around CTS issues.
//
// public static class Fair extends BlockingQueueTest {
@@ -34,19 +34,17 @@
// return new ArrayBlockingQueue(SIZE, true);
// }
// }
-
+ //
// public static class NonFair extends BlockingQueueTest {
// protected BlockingQueue emptyCollection() {
// return new ArrayBlockingQueue(SIZE, false);
// }
// }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(ArrayBlockingQueueTest.class,
// new Fair().testSuite(),
@@ -111,7 +109,7 @@
*/
public void testConstructor5() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = i;
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -173,7 +171,7 @@
assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.remainingCapacity());
assertEquals(SIZE, q.size() + q.remainingCapacity());
assertTrue(q.add(i));
}
@@ -221,7 +219,7 @@
public void testAddAll3() {
ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
try {
q.addAll(Arrays.asList(ints));
@@ -458,23 +456,25 @@
final CountDownLatch aboutToWait = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
+ long t0 = System.nanoTime();
aboutToWait.countDown();
try {
- q.poll(LONG_DELAY_MS, MILLISECONDS);
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
}
}});
- await(aboutToWait);
- waitForThreadToEnterWaitState(t, LONG_DELAY_MS);
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
checkEmpty(q);
}
@@ -577,7 +577,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -590,7 +590,7 @@
ArrayBlockingQueue q = populatedQueue(SIZE);
ArrayBlockingQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -624,23 +624,23 @@
checkToArray(q);
assertEquals(i, q.poll());
checkToArray(q);
- q.add(SIZE + i);
+ q.add(SIZE+i);
}
for (int i = 0; i < SIZE; i++) {
checkToArray(q);
- assertEquals(SIZE + i, q.poll());
+ assertEquals(SIZE+i, q.poll());
}
}
void checkToArray2(ArrayBlockingQueue q) {
int size = q.size();
- Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
+ Integer[] a1 = size == 0 ? null : new Integer[size-1];
Integer[] a2 = new Integer[size];
- Integer[] a3 = new Integer[size + 2];
+ Integer[] a3 = new Integer[size+2];
if (size > 0) Arrays.fill(a1, 42);
Arrays.fill(a2, 42);
Arrays.fill(a3, 42);
- Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
+ Integer[] b1 = size == 0 ? null : (Integer[]) q.toArray(a1);
Integer[] b2 = (Integer[]) q.toArray(a2);
Integer[] b3 = (Integer[]) q.toArray(a3);
assertSame(a2, b2);
@@ -654,7 +654,7 @@
assertSame(b3[i], x);
}
assertNull(a3[size]);
- assertEquals(42, (int) a3[size + 1]);
+ assertEquals(42, (int) a3[size+1]);
if (size > 0) {
assertNotSame(a1, b1);
assertEquals(size, b1.length);
@@ -678,11 +678,11 @@
checkToArray2(q);
assertEquals(i, q.poll());
checkToArray2(q);
- q.add(SIZE + i);
+ q.add(SIZE+i);
}
for (int i = 0; i < SIZE; i++) {
checkToArray2(q);
- assertEquals(SIZE + i, q.poll());
+ assertEquals(SIZE+i, q.poll());
}
}
@@ -793,24 +793,24 @@
final ArrayBlockingQueue q = new ArrayBlockingQueue(2);
q.add(one);
q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertFalse(q.offer(three));
- threadsStarted.await();
- assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
- assertEquals(0, q.remainingCapacity());
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- assertEquals(0, q.remainingCapacity());
- assertSame(one, q.take());
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertEquals(0, q.remainingCapacity());
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
}
/**
@@ -819,22 +819,22 @@
public void testPollInExecutor() {
final ArrayBlockingQueue q = new ArrayBlockingQueue(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- checkEmpty(q);
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -886,7 +886,7 @@
final ArrayBlockingQueue q = populatedQueue(SIZE);
Thread t = new Thread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- q.put(new Integer(SIZE + 1));
+ q.put(new Integer(SIZE+1));
}});
t.start();
@@ -903,7 +903,7 @@
* drainTo(c, n) empties first min(n, size) elements of queue into c
*/
public void testDrainToN() {
- ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE * 2);
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE*2);
for (int i = 0; i < SIZE + 2; ++i) {
for (int j = 0; j < SIZE; j++)
assertTrue(q.offer(new Integer(j)));
@@ -911,7 +911,7 @@
q.drainTo(l, i);
int k = (i < SIZE) ? i : SIZE;
assertEquals(k, l.size());
- assertEquals(SIZE - k, q.size());
+ assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
do {} while (q.poll() != null);
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
index 23cc6b9..16290e9 100644
--- a/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
@@ -26,7 +26,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ArrayDequeTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -65,7 +65,8 @@
*/
public void testConstructor4() {
try {
- new ArrayDeque(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new ArrayDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -74,10 +75,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new ArrayDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -115,7 +116,7 @@
public void testSize() {
ArrayDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.removeFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -128,8 +129,8 @@
* push(null) throws NPE
*/
public void testPushNull() {
- ArrayDeque q = new ArrayDeque(1);
try {
+ ArrayDeque q = new ArrayDeque(1);
q.push(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -163,8 +164,8 @@
* offer(null) throws NPE
*/
public void testOfferNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.offer(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -174,8 +175,8 @@
* offerFirst(null) throws NPE
*/
public void testOfferFirstNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.offerFirst(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -185,8 +186,8 @@
* offerLast(null) throws NPE
*/
public void testOfferLastNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.offerLast(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -229,8 +230,8 @@
* add(null) throws NPE
*/
public void testAddNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -240,8 +241,8 @@
* addFirst(null) throws NPE
*/
public void testAddFirstNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.addFirst(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -251,8 +252,8 @@
* addLast(null) throws NPE
*/
public void testAddLastNull() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.addLast(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -295,8 +296,8 @@
* addAll(null) throws NPE
*/
public void testAddAll1() {
- ArrayDeque q = new ArrayDeque();
try {
+ ArrayDeque q = new ArrayDeque();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -306,9 +307,10 @@
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
- ArrayDeque q = new ArrayDeque();
try {
- q.addAll(Arrays.asList(new Integer[SIZE]));
+ ArrayDeque q = new ArrayDeque();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -318,11 +320,11 @@
* possibly adding some elements
*/
public void testAddAll3() {
- ArrayDeque q = new ArrayDeque();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ ArrayDeque q = new ArrayDeque();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -359,7 +361,7 @@
*/
public void testPollLast() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollLast());
@@ -399,14 +401,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -444,7 +446,7 @@
*/
public void testPeekLast() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.peekLast());
assertEquals(i, q.pollLast());
assertTrue(q.peekLast() == null ||
@@ -488,7 +490,7 @@
*/
public void testLastElement() {
ArrayDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.getLast());
assertEquals(i, q.pollLast());
}
@@ -539,7 +541,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
- assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -554,7 +556,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
- assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -609,7 +611,7 @@
boolean changed = q.retainAll(p);
assertEquals(changed, (i > 0));
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.removeFirst();
}
}
@@ -622,7 +624,7 @@
ArrayDeque q = populatedDeque(SIZE);
ArrayDeque p = populatedDeque(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
assertFalse(q.contains(p.removeFirst()));
}
@@ -654,23 +656,23 @@
for (int i = 0; i < SIZE; i++) {
checkToArray(q);
assertEquals(i, q.poll());
- q.addLast(SIZE + i);
+ q.addLast(SIZE+i);
}
for (int i = 0; i < SIZE; i++) {
checkToArray(q);
- assertEquals(SIZE + i, q.poll());
+ assertEquals(SIZE+i, q.poll());
}
}
void checkToArray2(ArrayDeque q) {
int size = q.size();
- Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
+ Integer[] a1 = size == 0 ? null : new Integer[size-1];
Integer[] a2 = new Integer[size];
- Integer[] a3 = new Integer[size + 2];
+ Integer[] a3 = new Integer[size+2];
if (size > 0) Arrays.fill(a1, 42);
Arrays.fill(a2, 42);
Arrays.fill(a3, 42);
- Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
+ Integer[] b1 = size == 0 ? null : (Integer[]) q.toArray(a1);
Integer[] b2 = (Integer[]) q.toArray(a2);
Integer[] b3 = (Integer[]) q.toArray(a3);
assertSame(a2, b2);
@@ -684,7 +686,7 @@
assertSame(b3[i], x);
}
assertNull(a3[size]);
- assertEquals(42, (int) a3[size + 1]);
+ assertEquals(42, (int) a3[size+1]);
if (size > 0) {
assertNotSame(a1, b1);
assertEquals(size, b1.length);
@@ -707,11 +709,11 @@
for (int i = 0; i < SIZE; i++) {
checkToArray2(q);
assertEquals(i, q.poll());
- q.addLast(SIZE + i);
+ q.addLast(SIZE+i);
}
for (int i = 0; i < SIZE; i++) {
checkToArray2(q);
- assertEquals(SIZE + i, q.poll());
+ assertEquals(SIZE+i, q.poll());
}
}
@@ -785,18 +787,18 @@
final Random rng = new Random();
for (int iters = 0; iters < 100; ++iters) {
int max = rng.nextInt(5) + 2;
- int split = rng.nextInt(max - 1) + 1;
+ int split = rng.nextInt(max-1) + 1;
for (int j = 1; j <= max; ++j)
q.add(new Integer(j));
Iterator it = q.iterator();
for (int j = 1; j <= split; ++j)
assertEquals(it.next(), new Integer(j));
it.remove();
- assertEquals(it.next(), new Integer(split + 1));
+ assertEquals(it.next(), new Integer(split+1));
for (int j = 1; j <= split; ++j)
q.remove(new Integer(j));
it = q.iterator();
- for (int j = split + 1; j <= max; ++j) {
+ for (int j = split+1; j <= max; ++j) {
assertEquals(it.next(), new Integer(j));
it.remove();
}
@@ -853,18 +855,18 @@
final Random rng = new Random();
for (int iters = 0; iters < 100; ++iters) {
int max = rng.nextInt(5) + 2;
- int split = rng.nextInt(max - 1) + 1;
+ int split = rng.nextInt(max-1) + 1;
for (int j = max; j >= 1; --j)
q.add(new Integer(j));
Iterator it = q.descendingIterator();
for (int j = 1; j <= split; ++j)
assertEquals(it.next(), new Integer(j));
it.remove();
- assertEquals(it.next(), new Integer(split + 1));
+ assertEquals(it.next(), new Integer(split+1));
for (int j = 1; j <= split; ++j)
q.remove(new Integer(j));
it = q.descendingIterator();
- for (int j = split + 1; j <= max; ++j) {
+ for (int j = split+1; j <= max; ++j) {
assertEquals(it.next(), new Integer(j));
it.remove();
}
diff --git a/jsr166-tests/src/test/java/jsr166/Atomic8Test.java b/jsr166-tests/src/test/java/jsr166/Atomic8Test.java
deleted file mode 100644
index f81c44f..0000000
--- a/jsr166-tests/src/test/java/jsr166/Atomic8Test.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicIntegerArray;
-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicLongArray;
-import java.util.concurrent.atomic.AtomicLongFieldUpdater;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.atomic.AtomicReferenceArray;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class Atomic8Test extends JSR166TestCase {
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(Atomic8Test.class);
- // }
-
- /*
- * Tests of atomic class methods accepting lambdas
- * introduced in JDK8.
- */
-
- static long addLong17(long x) { return x + 17; }
- static int addInt17(int x) { return x + 17; }
- static Integer addInteger17(Integer x) {
- return new Integer(x.intValue() + 17);
- }
- static Integer sumInteger(Integer x, Integer y) {
- return new Integer(x.intValue() + y.intValue());
- }
-
- volatile long aLongField;
- volatile int anIntField;
- volatile Integer anIntegerField;
-
- AtomicLongFieldUpdater aLongFieldUpdater() {
- return AtomicLongFieldUpdater.newUpdater
- (Atomic8Test.class, "aLongField");
- }
-
- AtomicIntegerFieldUpdater anIntFieldUpdater() {
- return AtomicIntegerFieldUpdater.newUpdater
- (Atomic8Test.class, "anIntField");
- }
-
- AtomicReferenceFieldUpdater<Atomic8Test,Integer> anIntegerFieldUpdater() {
- return AtomicReferenceFieldUpdater.newUpdater
- (Atomic8Test.class, Integer.class, "anIntegerField");
- }
-
- /**
- * AtomicLong getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testLongGetAndUpdate() {
- AtomicLong a = new AtomicLong(1L);
- assertEquals(1L, a.getAndUpdate(Atomic8Test::addLong17));
- assertEquals(18L, a.getAndUpdate(Atomic8Test::addLong17));
- assertEquals(35L, a.get());
- }
-
- /**
- * AtomicLong updateAndGet updates with supplied function and
- * returns result.
- */
- public void testLongUpdateAndGet() {
- AtomicLong a = new AtomicLong(1L);
- assertEquals(18L, a.updateAndGet(Atomic8Test::addLong17));
- assertEquals(35L, a.updateAndGet(Atomic8Test::addLong17));
- }
-
- /**
- * AtomicLong getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testLongGetAndAccumulate() {
- AtomicLong a = new AtomicLong(1L);
- assertEquals(1L, a.getAndAccumulate(2L, Long::sum));
- assertEquals(3L, a.getAndAccumulate(3L, Long::sum));
- assertEquals(6L, a.get());
- }
-
- /**
- * AtomicLong accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testLongAccumulateAndGet() {
- AtomicLong a = new AtomicLong(1L);
- assertEquals(7L, a.accumulateAndGet(6L, Long::sum));
- assertEquals(10L, a.accumulateAndGet(3L, Long::sum));
- assertEquals(10L, a.get());
- }
-
- /**
- * AtomicInteger getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testIntGetAndUpdate() {
- AtomicInteger a = new AtomicInteger(1);
- assertEquals(1, a.getAndUpdate(Atomic8Test::addInt17));
- assertEquals(18, a.getAndUpdate(Atomic8Test::addInt17));
- assertEquals(35, a.get());
- }
-
- /**
- * AtomicInteger updateAndGet updates with supplied function and
- * returns result.
- */
- public void testIntUpdateAndGet() {
- AtomicInteger a = new AtomicInteger(1);
- assertEquals(18, a.updateAndGet(Atomic8Test::addInt17));
- assertEquals(35, a.updateAndGet(Atomic8Test::addInt17));
- assertEquals(35, a.get());
- }
-
- /**
- * AtomicInteger getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testIntGetAndAccumulate() {
- AtomicInteger a = new AtomicInteger(1);
- assertEquals(1, a.getAndAccumulate(2, Integer::sum));
- assertEquals(3, a.getAndAccumulate(3, Integer::sum));
- assertEquals(6, a.get());
- }
-
- /**
- * AtomicInteger accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testIntAccumulateAndGet() {
- AtomicInteger a = new AtomicInteger(1);
- assertEquals(7, a.accumulateAndGet(6, Integer::sum));
- assertEquals(10, a.accumulateAndGet(3, Integer::sum));
- assertEquals(10, a.get());
- }
-
- /**
- * AtomicReference getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testReferenceGetAndUpdate() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
- assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17));
- assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.get());
- }
-
- /**
- * AtomicReference updateAndGet updates with supplied function and
- * returns result.
- */
- public void testReferenceUpdateAndGet() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
- assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.get());
- }
-
- /**
- * AtomicReference getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testReferenceGetAndAccumulate() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
- assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger));
- assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger));
- assertEquals(new Integer(6), a.get());
- }
-
- /**
- * AtomicReference accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testReferenceAccumulateAndGet() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
- assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger));
- assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger));
- assertEquals(new Integer(10), a.get());
- }
-
- /**
- * AtomicLongArray getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testLongArrayGetAndUpdate() {
- AtomicLongArray a = new AtomicLongArray(1);
- a.set(0, 1);
- assertEquals(1L, a.getAndUpdate(0, Atomic8Test::addLong17));
- assertEquals(18L, a.getAndUpdate(0, Atomic8Test::addLong17));
- assertEquals(35L, a.get(0));
- }
-
- /**
- * AtomicLongArray updateAndGet updates with supplied function and
- * returns result.
- */
- public void testLongArrayUpdateAndGet() {
- AtomicLongArray a = new AtomicLongArray(1);
- a.set(0, 1);
- assertEquals(18L, a.updateAndGet(0, Atomic8Test::addLong17));
- assertEquals(35L, a.updateAndGet(0, Atomic8Test::addLong17));
- assertEquals(35L, a.get(0));
- }
-
- /**
- * AtomicLongArray getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testLongArrayGetAndAccumulate() {
- AtomicLongArray a = new AtomicLongArray(1);
- a.set(0, 1);
- assertEquals(1L, a.getAndAccumulate(0, 2L, Long::sum));
- assertEquals(3L, a.getAndAccumulate(0, 3L, Long::sum));
- assertEquals(6L, a.get(0));
- }
-
- /**
- * AtomicLongArray accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testLongArrayAccumulateAndGet() {
- AtomicLongArray a = new AtomicLongArray(1);
- a.set(0, 1);
- assertEquals(7L, a.accumulateAndGet(0, 6L, Long::sum));
- assertEquals(10L, a.accumulateAndGet(0, 3L, Long::sum));
- assertEquals(10L, a.get(0));
- }
-
- /**
- * AtomicIntegerArray getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testIntArrayGetAndUpdate() {
- AtomicIntegerArray a = new AtomicIntegerArray(1);
- a.set(0, 1);
- assertEquals(1, a.getAndUpdate(0, Atomic8Test::addInt17));
- assertEquals(18, a.getAndUpdate(0, Atomic8Test::addInt17));
- assertEquals(35, a.get(0));
- }
-
- /**
- * AtomicIntegerArray updateAndGet updates with supplied function and
- * returns result.
- */
- public void testIntArrayUpdateAndGet() {
- AtomicIntegerArray a = new AtomicIntegerArray(1);
- a.set(0, 1);
- assertEquals(18, a.updateAndGet(0, Atomic8Test::addInt17));
- assertEquals(35, a.updateAndGet(0, Atomic8Test::addInt17));
- assertEquals(35, a.get(0));
- }
-
- /**
- * AtomicIntegerArray getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testIntArrayGetAndAccumulate() {
- AtomicIntegerArray a = new AtomicIntegerArray(1);
- a.set(0, 1);
- assertEquals(1, a.getAndAccumulate(0, 2, Integer::sum));
- assertEquals(3, a.getAndAccumulate(0, 3, Integer::sum));
- assertEquals(6, a.get(0));
- }
-
- /**
- * AtomicIntegerArray accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testIntArrayAccumulateAndGet() {
- AtomicIntegerArray a = new AtomicIntegerArray(1);
- a.set(0, 1);
- assertEquals(7, a.accumulateAndGet(0, 6, Integer::sum));
- assertEquals(10, a.accumulateAndGet(0, 3, Integer::sum));
- }
-
- /**
- * AtomicReferenceArray getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testReferenceArrayGetAndUpdate() {
- AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
- a.set(0, one);
- assertEquals(new Integer(1), a.getAndUpdate(0, Atomic8Test::addInteger17));
- assertEquals(new Integer(18), a.getAndUpdate(0, Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.get(0));
- }
-
- /**
- * AtomicReferenceArray updateAndGet updates with supplied function and
- * returns result.
- */
- public void testReferenceArrayUpdateAndGet() {
- AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
- a.set(0, one);
- assertEquals(new Integer(18), a.updateAndGet(0, Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.updateAndGet(0, Atomic8Test::addInteger17));
- }
-
- /**
- * AtomicReferenceArray getAndAccumulate returns previous value and updates
- * with supplied function.
- */
- public void testReferenceArrayGetAndAccumulate() {
- AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
- a.set(0, one);
- assertEquals(new Integer(1), a.getAndAccumulate(0, 2, Atomic8Test::sumInteger));
- assertEquals(new Integer(3), a.getAndAccumulate(0, 3, Atomic8Test::sumInteger));
- assertEquals(new Integer(6), a.get(0));
- }
-
- /**
- * AtomicReferenceArray accumulateAndGet updates with supplied function and
- * returns result.
- */
- public void testReferenceArrayAccumulateAndGet() {
- AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
- a.set(0, one);
- assertEquals(new Integer(7), a.accumulateAndGet(0, 6, Atomic8Test::sumInteger));
- assertEquals(new Integer(10), a.accumulateAndGet(0, 3, Atomic8Test::sumInteger));
- }
-
- /**
- * AtomicLongFieldUpdater getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testLongFieldUpdaterGetAndUpdate() {
- AtomicLongFieldUpdater a = aLongFieldUpdater();
- a.set(this, 1);
- assertEquals(1L, a.getAndUpdate(this, Atomic8Test::addLong17));
- assertEquals(18L, a.getAndUpdate(this, Atomic8Test::addLong17));
- assertEquals(35L, a.get(this));
- assertEquals(35L, aLongField);
- }
-
- /**
- * AtomicLongFieldUpdater updateAndGet updates with supplied function and
- * returns result.
- */
- public void testLongFieldUpdaterUpdateAndGet() {
- AtomicLongFieldUpdater a = aLongFieldUpdater();
- a.set(this, 1);
- assertEquals(18L, a.updateAndGet(this, Atomic8Test::addLong17));
- assertEquals(35L, a.updateAndGet(this, Atomic8Test::addLong17));
- assertEquals(35L, a.get(this));
- assertEquals(35L, aLongField);
- }
-
- /**
- * AtomicLongFieldUpdater getAndAccumulate returns previous value
- * and updates with supplied function.
- */
- public void testLongFieldUpdaterGetAndAccumulate() {
- AtomicLongFieldUpdater a = aLongFieldUpdater();
- a.set(this, 1);
- assertEquals(1L, a.getAndAccumulate(this, 2L, Long::sum));
- assertEquals(3L, a.getAndAccumulate(this, 3L, Long::sum));
- assertEquals(6L, a.get(this));
- assertEquals(6L, aLongField);
- }
-
- /**
- * AtomicLongFieldUpdater accumulateAndGet updates with supplied
- * function and returns result.
- */
- public void testLongFieldUpdaterAccumulateAndGet() {
- AtomicLongFieldUpdater a = aLongFieldUpdater();
- a.set(this, 1);
- assertEquals(7L, a.accumulateAndGet(this, 6L, Long::sum));
- assertEquals(10L, a.accumulateAndGet(this, 3L, Long::sum));
- assertEquals(10L, a.get(this));
- assertEquals(10L, aLongField);
- }
-
- /**
- * AtomicIntegerFieldUpdater getAndUpdate returns previous value and updates
- * result of supplied function
- */
- public void testIntegerFieldUpdaterGetAndUpdate() {
- AtomicIntegerFieldUpdater a = anIntFieldUpdater();
- a.set(this, 1);
- assertEquals(1, a.getAndUpdate(this, Atomic8Test::addInt17));
- assertEquals(18, a.getAndUpdate(this, Atomic8Test::addInt17));
- assertEquals(35, a.get(this));
- assertEquals(35, anIntField);
- }
-
- /**
- * AtomicIntegerFieldUpdater updateAndGet updates with supplied function and
- * returns result.
- */
- public void testIntegerFieldUpdaterUpdateAndGet() {
- AtomicIntegerFieldUpdater a = anIntFieldUpdater();
- a.set(this, 1);
- assertEquals(18, a.updateAndGet(this, Atomic8Test::addInt17));
- assertEquals(35, a.updateAndGet(this, Atomic8Test::addInt17));
- assertEquals(35, a.get(this));
- assertEquals(35, anIntField);
- }
-
- /**
- * AtomicIntegerFieldUpdater getAndAccumulate returns previous value
- * and updates with supplied function.
- */
- public void testIntegerFieldUpdaterGetAndAccumulate() {
- AtomicIntegerFieldUpdater a = anIntFieldUpdater();
- a.set(this, 1);
- assertEquals(1, a.getAndAccumulate(this, 2, Integer::sum));
- assertEquals(3, a.getAndAccumulate(this, 3, Integer::sum));
- assertEquals(6, a.get(this));
- assertEquals(6, anIntField);
- }
-
- /**
- * AtomicIntegerFieldUpdater accumulateAndGet updates with supplied
- * function and returns result.
- */
- public void testIntegerFieldUpdaterAccumulateAndGet() {
- AtomicIntegerFieldUpdater a = anIntFieldUpdater();
- a.set(this, 1);
- assertEquals(7, a.accumulateAndGet(this, 6, Integer::sum));
- assertEquals(10, a.accumulateAndGet(this, 3, Integer::sum));
- assertEquals(10, a.get(this));
- assertEquals(10, anIntField);
- }
-
- /**
- * AtomicReferenceFieldUpdater getAndUpdate returns previous value
- * and updates result of supplied function
- */
- public void testReferenceFieldUpdaterGetAndUpdate() {
- AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
- a.set(this, one);
- assertEquals(new Integer(1), a.getAndUpdate(this, Atomic8Test::addInteger17));
- assertEquals(new Integer(18), a.getAndUpdate(this, Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.get(this));
- assertEquals(new Integer(35), anIntegerField);
- }
-
- /**
- * AtomicReferenceFieldUpdater updateAndGet updates with supplied
- * function and returns result.
- */
- public void testReferenceFieldUpdaterUpdateAndGet() {
- AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
- a.set(this, one);
- assertEquals(new Integer(18), a.updateAndGet(this, Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.updateAndGet(this, Atomic8Test::addInteger17));
- assertEquals(new Integer(35), a.get(this));
- assertEquals(new Integer(35), anIntegerField);
- }
-
- /**
- * AtomicReferenceFieldUpdater returns previous value and updates
- * with supplied function.
- */
- public void testReferenceFieldUpdaterGetAndAccumulate() {
- AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
- a.set(this, one);
- assertEquals(new Integer(1), a.getAndAccumulate(this, 2, Atomic8Test::sumInteger));
- assertEquals(new Integer(3), a.getAndAccumulate(this, 3, Atomic8Test::sumInteger));
- assertEquals(new Integer(6), a.get(this));
- assertEquals(new Integer(6), anIntegerField);
- }
-
- /**
- * AtomicReferenceFieldUpdater accumulateAndGet updates with
- * supplied function and returns result.
- */
- public void testReferenceFieldUpdaterAccumulateAndGet() {
- AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
- a.set(this, one);
- assertEquals(new Integer(7), a.accumulateAndGet(this, 6, Atomic8Test::sumInteger));
- assertEquals(new Integer(10), a.accumulateAndGet(this, 3, Atomic8Test::sumInteger));
- assertEquals(new Integer(10), a.get(this));
- assertEquals(new Integer(10), anIntegerField);
- }
-
- /**
- * All Atomic getAndUpdate methods throw NullPointerException on
- * null function argument
- */
- public void testGetAndUpdateNPE() {
- Runnable[] throwingActions = {
- () -> new AtomicLong().getAndUpdate(null),
- () -> new AtomicInteger().getAndUpdate(null),
- () -> new AtomicReference().getAndUpdate(null),
- () -> new AtomicLongArray(1).getAndUpdate(0, null),
- () -> new AtomicIntegerArray(1).getAndUpdate(0, null),
- () -> new AtomicReferenceArray(1).getAndUpdate(0, null),
- () -> aLongFieldUpdater().getAndUpdate(this, null),
- () -> anIntFieldUpdater().getAndUpdate(this, null),
- () -> anIntegerFieldUpdater().getAndUpdate(this, null),
- ////() -> aLongFieldUpdater().getAndUpdate(null, Atomic8Test::addLong17),
- ////() -> anIntFieldUpdater().getAndUpdate(null, Atomic8Test::addInt17),
- ////() -> anIntegerFieldUpdater().getAndUpdate(null, Atomic8Test::addInteger17),
- };
- assertThrows(NullPointerException.class, throwingActions);
- }
-
- /**
- * All Atomic updateAndGet methods throw NullPointerException on null function argument
- */
- public void testUpdateAndGetNPE() {
- Runnable[] throwingActions = {
- () -> new AtomicLong().updateAndGet(null),
- () -> new AtomicInteger().updateAndGet(null),
- () -> new AtomicReference().updateAndGet(null),
- () -> new AtomicLongArray(1).updateAndGet(0, null),
- () -> new AtomicIntegerArray(1).updateAndGet(0, null),
- () -> new AtomicReferenceArray(1).updateAndGet(0, null),
- () -> aLongFieldUpdater().updateAndGet(this, null),
- () -> anIntFieldUpdater().updateAndGet(this, null),
- () -> anIntegerFieldUpdater().updateAndGet(this, null),
- };
- assertThrows(NullPointerException.class, throwingActions);
- }
-
- /**
- * All Atomic getAndAccumulate methods throw NullPointerException
- * on null function argument
- */
- public void testGetAndAccumulateNPE() {
- Runnable[] throwingActions = {
- () -> new AtomicLong().getAndAccumulate(1L, null),
- () -> new AtomicInteger().getAndAccumulate(1, null),
- () -> new AtomicReference().getAndAccumulate(one, null),
- () -> new AtomicLongArray(1).getAndAccumulate(0, 1L, null),
- () -> new AtomicIntegerArray(1).getAndAccumulate(0, 1, null),
- () -> new AtomicReferenceArray(1).getAndAccumulate(0, one, null),
- () -> aLongFieldUpdater().getAndAccumulate(this, 1L, null),
- () -> anIntFieldUpdater().getAndAccumulate(this, 1, null),
- () -> anIntegerFieldUpdater().getAndAccumulate(this, one, null),
- };
- assertThrows(NullPointerException.class, throwingActions);
- }
-
- /**
- * All Atomic accumulateAndGet methods throw NullPointerException
- * on null function argument
- */
- public void testAccumulateAndGetNPE() {
- Runnable[] throwingActions = {
- () -> new AtomicLong().accumulateAndGet(1L, null),
- () -> new AtomicInteger().accumulateAndGet(1, null),
- () -> new AtomicReference().accumulateAndGet(one, null),
- () -> new AtomicLongArray(1).accumulateAndGet(0, 1L, null),
- () -> new AtomicIntegerArray(1).accumulateAndGet(0, 1, null),
- () -> new AtomicReferenceArray(1).accumulateAndGet(0, one, null),
- () -> aLongFieldUpdater().accumulateAndGet(this, 1L, null),
- () -> anIntFieldUpdater().accumulateAndGet(this, 1, null),
- () -> anIntegerFieldUpdater().accumulateAndGet(this, one, null),
- };
- assertThrows(NullPointerException.class, throwingActions);
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
index 6f5decf..bfe3fc6 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicBooleanTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
index c9e32aa..670b9ce 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
@@ -15,7 +15,6 @@
import junit.framework.TestSuite;
public class AtomicIntegerArrayTest extends JSR166TestCase {
-
// android-note: Removed because the CTS runner does a bad job of
// retrying tests that have suite() declarations.
//
@@ -23,7 +22,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicIntegerArrayTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -291,7 +290,7 @@
assertTrue(v >= 0);
if (v != 0) {
done = false;
- if (aa.compareAndSet(i, v, v - 1))
+ if (aa.compareAndSet(i, v, v-1))
++counts;
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
index c8d3856..ef75b46 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
@@ -15,10 +15,8 @@
public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase {
volatile int x = 0;
- protected volatile int protectedField;
- private volatile int privateField;
int w;
- float z;
+ long z;
// android-note: Removed because the CTS runner does a bad job of
// retrying tests that have suite() declarations.
//
@@ -26,59 +24,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicIntegerFieldUpdaterTest.class);
- // }
-
- // for testing subclass access
- // android-note: Removed because android doesn't restrict reflection access
- // static class AtomicIntegerFieldUpdaterTestSubclass extends AtomicIntegerFieldUpdaterTest {
- // public void checkPrivateAccess() {
- // try {
- // AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- // AtomicIntegerFieldUpdater.newUpdater
- // (AtomicIntegerFieldUpdaterTest.class, "privateField");
- // shouldThrow();
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
-
- // public void checkCompareAndSetProtectedSub() {
- // AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- // AtomicIntegerFieldUpdater.newUpdater
- // (AtomicIntegerFieldUpdaterTest.class, "protectedField");
- // this.protectedField = 1;
- // assertTrue(a.compareAndSet(this, 1, 2));
- // assertTrue(a.compareAndSet(this, 2, -4));
- // assertEquals(-4, a.get(this));
- // assertFalse(a.compareAndSet(this, -5, 7));
- // assertEquals(-4, a.get(this));
- // assertTrue(a.compareAndSet(this, -4, 7));
- // assertEquals(7, a.get(this));
- // }
- // }
-
- // static class UnrelatedClass {
- // public void checkPackageAccess(AtomicIntegerFieldUpdaterTest obj) {
- // obj.x = 72;
- // AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- // AtomicIntegerFieldUpdater.newUpdater
- // (AtomicIntegerFieldUpdaterTest.class, "x");
- // assertEquals(72, a.get(obj));
- // assertTrue(a.compareAndSet(obj, 72, 73));
- // assertEquals(73, a.get(obj));
- // }
-
- // public void checkPrivateAccess(AtomicIntegerFieldUpdaterTest obj) {
- // try {
- // AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- // AtomicIntegerFieldUpdater.newUpdater
- // (AtomicIntegerFieldUpdaterTest.class, "privateField");
- // throw new AssertionError("should throw");
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
+ // return new TestSuite(...);
// }
AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> updaterFor(String fieldName) {
@@ -119,26 +65,6 @@
}
/**
- * construction using private field from subclass throws RuntimeException
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testPrivateFieldInSubclass() {
- // AtomicIntegerFieldUpdaterTestSubclass s =
- // new AtomicIntegerFieldUpdaterTestSubclass();
- // s.checkPrivateAccess();
- // }
-
- /**
- * construction from unrelated class; package access is allowed,
- * private access is not
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testUnrelatedClassAccess() {
- // new UnrelatedClass().checkPackageAccess(this);
- // new UnrelatedClass().checkPrivateAccess(this);
- // }
-
- /**
* get returns the last value set or assigned
*/
public void testGetSet() {
@@ -183,34 +109,6 @@
}
/**
- * compareAndSet succeeds in changing protected field value if
- * equal to expected else fails
- */
- public void testCompareAndSetProtected() {
- AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
- a = updaterFor("protectedField");
- protectedField = 1;
- assertTrue(a.compareAndSet(this, 1, 2));
- assertTrue(a.compareAndSet(this, 2, -4));
- assertEquals(-4, a.get(this));
- assertFalse(a.compareAndSet(this, -5, 7));
- assertEquals(-4, a.get(this));
- assertTrue(a.compareAndSet(this, -4, 7));
- assertEquals(7, a.get(this));
- }
-
- /**
- * compareAndSet succeeds in changing protected field value if
- * equal to expected else fails
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testCompareAndSetProtectedInSubclass() {
- // AtomicIntegerFieldUpdaterTestSubclass s =
- // new AtomicIntegerFieldUpdaterTestSubclass();
- // s.checkCompareAndSetProtectedSub();
- // }
-
- /**
* compareAndSet in one thread enables another waiting for value
* to succeed
*/
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
index 6392c54..cf73810 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicIntegerTest.class);
+ // return new TestSuite(...);
// }
final int[] VALUES = {
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
index a60ecfd..08df01e 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
@@ -22,7 +22,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicLongArrayTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -290,7 +290,7 @@
assertTrue(v >= 0);
if (v != 0) {
done = false;
- if (aa.compareAndSet(i, v, v - 1))
+ if (aa.compareAndSet(i, v, v-1))
++counts;
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
index d46280b..204f814 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
@@ -15,10 +15,9 @@
public class AtomicLongFieldUpdaterTest extends JSR166TestCase {
volatile long x = 0;
- protected volatile long protectedField;
- private volatile long privateField;
+ int z;
long w;
- float z;
+
// android-note: Removed because the CTS runner does a bad job of
// retrying tests that have suite() declarations.
//
@@ -26,59 +25,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicLongFieldUpdaterTest.class);
- // }
-
- // for testing subclass access
- // android-note: Removed because android doesn't restrict reflection access
- // static class AtomicLongFieldUpdaterTestSubclass extends AtomicLongFieldUpdaterTest {
- // public void checkPrivateAccess() {
- // try {
- // AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- // AtomicLongFieldUpdater.newUpdater
- // (AtomicLongFieldUpdaterTest.class, "privateField");
- // shouldThrow();
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
-
- // public void checkCompareAndSetProtectedSub() {
- // AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- // AtomicLongFieldUpdater.newUpdater
- // (AtomicLongFieldUpdaterTest.class, "protectedField");
- // this.protectedField = 1;
- // assertTrue(a.compareAndSet(this, 1, 2));
- // assertTrue(a.compareAndSet(this, 2, -4));
- // assertEquals(-4, a.get(this));
- // assertFalse(a.compareAndSet(this, -5, 7));
- // assertEquals(-4, a.get(this));
- // assertTrue(a.compareAndSet(this, -4, 7));
- // assertEquals(7, a.get(this));
- // }
- // }
-
- // static class UnrelatedClass {
- // public void checkPackageAccess(AtomicLongFieldUpdaterTest obj) {
- // obj.x = 72L;
- // AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- // AtomicLongFieldUpdater.newUpdater
- // (AtomicLongFieldUpdaterTest.class, "x");
- // assertEquals(72L, a.get(obj));
- // assertTrue(a.compareAndSet(obj, 72L, 73L));
- // assertEquals(73L, a.get(obj));
- // }
-
- // public void checkPrivateAccess(AtomicLongFieldUpdaterTest obj) {
- // try {
- // AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- // AtomicLongFieldUpdater.newUpdater
- // (AtomicLongFieldUpdaterTest.class, "privateField");
- // throw new AssertionError("should throw");
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
+ // return new TestSuite(...);
// }
AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> updaterFor(String fieldName) {
@@ -119,26 +66,6 @@
}
/**
- * construction using private field from subclass throws RuntimeException
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testPrivateFieldInSubclass() {
- // AtomicLongFieldUpdaterTestSubclass s =
- // new AtomicLongFieldUpdaterTestSubclass();
- // s.checkPrivateAccess();
- // }
-
- /**
- * construction from unrelated class; package access is allowed,
- * private access is not
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testUnrelatedClassAccess() {
- // new UnrelatedClass().checkPackageAccess(this);
- // new UnrelatedClass().checkPrivateAccess(this);
- // }
-
- /**
* get returns the last value set or assigned
*/
public void testGetSet() {
@@ -183,34 +110,6 @@
}
/**
- * compareAndSet succeeds in changing protected field value if
- * equal to expected else fails
- */
- public void testCompareAndSetProtected() {
- AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
- a = updaterFor("protectedField");
- protectedField = 1;
- assertTrue(a.compareAndSet(this, 1, 2));
- assertTrue(a.compareAndSet(this, 2, -4));
- assertEquals(-4, a.get(this));
- assertFalse(a.compareAndSet(this, -5, 7));
- assertEquals(-4, a.get(this));
- assertTrue(a.compareAndSet(this, -4, 7));
- assertEquals(7, a.get(this));
- }
-
- /**
- * compareAndSet succeeds in changing protected field value if
- * equal to expected else fails
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testCompareAndSetProtectedInSubclass() {
- // AtomicLongFieldUpdaterTestSubclass s =
- // new AtomicLongFieldUpdaterTestSubclass();
- // s.checkCompareAndSetProtectedSub();
- // }
-
- /**
* compareAndSet in one thread enables another waiting for value
* to succeed
*/
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
index a8ee7c6..b9c1722 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicLongTest.class);
+ // return new TestSuite(...);
// }
final long[] VALUES = {
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
index bd4e8cb..61b6b1b 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicMarkableReferenceTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
index f3aab44..1df2f9f 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
@@ -22,7 +22,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicReferenceArrayTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
index 9b2e9a9..4b0d946 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
@@ -15,8 +15,6 @@
public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
volatile Integer x = null;
- protected volatile Integer protectedField;
- private volatile Integer privateField;
Object z;
Integer w;
volatile int i;
@@ -28,62 +26,10 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicReferenceFieldUpdaterTest.class);
+ // return new TestSuite(...);
// }
- // for testing subclass access
- // android-note: Removed because android doesn't restrict reflection access
- // static class AtomicReferenceFieldUpdaterTestSubclass extends AtomicReferenceFieldUpdaterTest {
- // public void checkPrivateAccess() {
- // try {
- // AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- // AtomicReferenceFieldUpdater.newUpdater
- // (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
- // shouldThrow();
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
-
- // public void checkCompareAndSetProtectedSub() {
- // AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- // AtomicReferenceFieldUpdater.newUpdater
- // (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField");
- // this.protectedField = one;
- // assertTrue(a.compareAndSet(this, one, two));
- // assertTrue(a.compareAndSet(this, two, m4));
- // assertSame(m4, a.get(this));
- // assertFalse(a.compareAndSet(this, m5, seven));
- // assertFalse(seven == a.get(this));
- // assertTrue(a.compareAndSet(this, m4, seven));
- // assertSame(seven, a.get(this));
- // }
- // }
-
- // static class UnrelatedClass {
- // public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) {
- // obj.x = one;
- // AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- // AtomicReferenceFieldUpdater.newUpdater
- // (AtomicReferenceFieldUpdaterTest.class, Integer.class, "x");
- // assertSame(one, a.get(obj));
- // assertTrue(a.compareAndSet(obj, one, two));
- // assertSame(two, a.get(obj));
- // }
-
- // public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) {
- // try {
- // AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- // AtomicReferenceFieldUpdater.newUpdater
- // (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
- // throw new AssertionError("should throw");
- // } catch (RuntimeException success) {
- // assertNotNull(success.getCause());
- // }
- // }
- // }
-
- static AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
return AtomicReferenceFieldUpdater.newUpdater
(AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName);
}
@@ -131,26 +77,6 @@
}
/**
- * construction using private field from subclass throws RuntimeException
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testPrivateFieldInSubclass() {
- // AtomicReferenceFieldUpdaterTestSubclass s =
- // new AtomicReferenceFieldUpdaterTestSubclass();
- // s.checkPrivateAccess();
- // }
-
- /**
- * construction from unrelated class; package access is allowed,
- * private access is not
- */
- // android-note: Removed because android doesn't restrict reflection access
- // public void testUnrelatedClassAccess() {
- // new UnrelatedClass().checkPackageAccess(this);
- // new UnrelatedClass().checkPrivateAccess(this);
- // }
-
- /**
* get returns the last value set or assigned
*/
public void testGetSet() {
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
index 4728970..457182f 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicReferenceTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
index a2e8c7f..b3ff06a 100644
--- a/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
@@ -21,7 +21,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(AtomicStampedReferenceTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
index 1a188e1..db0f03d 100644
--- a/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
@@ -39,9 +39,9 @@
// android-note: Explicitly instantiated.
//
// public Test testSuite() {
- // // TODO: filter the returned tests using the configuration
- // // information provided by the subclass via protected methods.
- // return new TestSuite(this.getClass());
+ // // TODO: filter the returned tests using the configuration
+ // // information provided by the subclass via protected methods.
+ // return new TestSuite(this.getClass());
// }
//----------------------------------------------------------------
@@ -239,8 +239,6 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
-
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
barrier.await();
@@ -354,20 +352,20 @@
assertEquals((pass == 0), q.contains(elts[i]));
assertEquals((pass == 0), q.remove(elts[i]));
assertFalse(q.contains(elts[i]));
- assertTrue(q.contains(elts[i - 1]));
+ assertTrue(q.contains(elts[i-1]));
if (i < size - 1)
- assertTrue(q.contains(elts[i + 1]));
+ assertTrue(q.contains(elts[i+1]));
}
}
if (size > 0)
assertTrue(q.contains(elts[0]));
- for (int i = size - 2; i >= 0; i -= 2) {
+ for (int i = size-2; i >= 0; i -= 2) {
assertTrue(q.contains(elts[i]));
- assertFalse(q.contains(elts[i + 1]));
+ assertFalse(q.contains(elts[i+1]));
assertTrue(q.remove(elts[i]));
assertFalse(q.contains(elts[i]));
- assertFalse(q.remove(elts[i + 1]));
- assertFalse(q.contains(elts[i + 1]));
+ assertFalse(q.remove(elts[i+1]));
+ assertFalse(q.contains(elts[i+1]));
}
checkEmpty(q);
}
diff --git a/jsr166-tests/src/test/java/jsr166/Collection8Test.java b/jsr166-tests/src/test/java/jsr166/Collection8Test.java
deleted file mode 100644
index 634182b..0000000
--- a/jsr166-tests/src/test/java/jsr166/Collection8Test.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Consumer;
-
-import junit.framework.Test;
-
-/**
- * Contains tests applicable to all jdk8+ Collection implementations.
- * An extension of CollectionTest.
- */
-public class Collection8Test extends JSR166TestCase {
- final CollectionImplementation impl;
-
- /** Tests are parameterized by a Collection implementation. */
- Collection8Test(CollectionImplementation impl, String methodName) {
- super(methodName);
- this.impl = impl;
- }
-
- public static Test testSuite(CollectionImplementation impl) {
- return parameterizedTestSuite(Collection8Test.class,
- CollectionImplementation.class,
- impl);
- }
-
- /**
- * stream().forEach returns elements in the collection
- */
- // TODO(streams):
- // public void testForEach() throws Throwable {
- // final Collection c = impl.emptyCollection();
- // final AtomicLong count = new AtomicLong(0L);
- // final Object x = impl.makeElement(1);
- // final Object y = impl.makeElement(2);
- // final ArrayList found = new ArrayList();
- // Consumer<Object> spy = (o) -> { found.add(o); };
- // c.stream().forEach(spy);
- // assertTrue(found.isEmpty());
-
- // assertTrue(c.add(x));
- // c.stream().forEach(spy);
- // assertEquals(Collections.singletonList(x), found);
- // found.clear();
-
- // assertTrue(c.add(y));
- // c.stream().forEach(spy);
- // assertEquals(2, found.size());
- // assertTrue(found.contains(x));
- // assertTrue(found.contains(y));
- // found.clear();
-
- // c.clear();
- // c.stream().forEach(spy);
- // assertTrue(found.isEmpty());
- // }
-
- // public void testForEachConcurrentStressTest() throws Throwable {
- // if (!impl.isConcurrent()) return;
- // final Collection c = impl.emptyCollection();
- // final long testDurationMillis = timeoutMillis();
- // final AtomicBoolean done = new AtomicBoolean(false);
- // final Object elt = impl.makeElement(1);
- // final Future<?> f1, f2;
- // final ExecutorService pool = Executors.newCachedThreadPool();
- // try (PoolCleaner cleaner = cleaner(pool, done)) {
- // final CountDownLatch threadsStarted = new CountDownLatch(2);
- // Runnable checkElt = () -> {
- // threadsStarted.countDown();
- // while (!done.get())
- // c.stream().forEach((x) -> { assertSame(x, elt); }); };
- // Runnable addRemove = () -> {
- // threadsStarted.countDown();
- // while (!done.get()) {
- // assertTrue(c.add(elt));
- // assertTrue(c.remove(elt));
- // }};
- // f1 = pool.submit(checkElt);
- // f2 = pool.submit(addRemove);
- // Thread.sleep(testDurationMillis);
- // }
- // assertNull(f1.get(0L, MILLISECONDS));
- // assertNull(f2.get(0L, MILLISECONDS));
- // }
-
- // public void testCollection8DebugFail() { fail(); }
-}
diff --git a/jsr166-tests/src/test/java/jsr166/CollectionImplementation.java b/jsr166-tests/src/test/java/jsr166/CollectionImplementation.java
deleted file mode 100644
index 4ba5bda..0000000
--- a/jsr166-tests/src/test/java/jsr166/CollectionImplementation.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.Collection;
-
-/** Allows tests to work with different Collection implementations. */
-public interface CollectionImplementation {
- /** Returns the Collection class. */
- public Class<?> klazz();
- /** Returns an empty collection. */
- public Collection emptyCollection();
- public Object makeElement(int i);
- public boolean isConcurrent();
- public boolean permitsNulls();
-}
diff --git a/jsr166-tests/src/test/java/jsr166/CollectionTest.java b/jsr166-tests/src/test/java/jsr166/CollectionTest.java
deleted file mode 100644
index 44ef66d..0000000
--- a/jsr166-tests/src/test/java/jsr166/CollectionTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.Collection;
-
-import junit.framework.Test;
-
-/**
- * Contains tests applicable to all Collection implementations.
- */
-public class CollectionTest extends JSR166TestCase {
- final CollectionImplementation impl;
-
- /** Tests are parameterized by a Collection implementation. */
- CollectionTest(CollectionImplementation impl, String methodName) {
- super(methodName);
- this.impl = impl;
- }
-
- public static Test testSuite(CollectionImplementation impl) {
- return newTestSuite
- (parameterizedTestSuite(CollectionTest.class,
- CollectionImplementation.class,
- impl),
- jdk8ParameterizedTestSuite(CollectionTest.class,
- CollectionImplementation.class,
- impl));
- }
-
- /** A test of the CollectionImplementation implementation ! */
- public void testEmptyMeansEmpty() {
- assertTrue(impl.emptyCollection().isEmpty());
- assertEquals(0, impl.emptyCollection().size());
- }
-
- // public void testCollectionDebugFail() { fail(); }
-}
diff --git a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
deleted file mode 100644
index 1372cc4..0000000
--- a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
+++ /dev/null
@@ -1,3959 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static java.util.concurrent.CompletableFuture.completedFuture;
-import static java.util.concurrent.CompletableFuture.failedFuture;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-// TODO(streams):
-//import java.util.stream.Collectors;
-//import java.util.stream.Stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class CompletableFutureTest extends JSR166TestCase {
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(CompletableFutureTest.class);
- // }
-
- static class CFException extends RuntimeException {}
-
- void checkIncomplete(CompletableFuture<?> f) {
- assertFalse(f.isDone());
- assertFalse(f.isCancelled());
- assertTrue(f.toString().contains("Not completed"));
- try {
- assertNull(f.getNow(null));
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- try {
- f.get(0L, SECONDS);
- shouldThrow();
- }
- catch (TimeoutException success) {}
- catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- <T> void checkCompletedNormally(CompletableFuture<T> f, T value) {
- checkTimedGet(f, value);
-
- try {
- assertEquals(value, f.join());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- try {
- assertEquals(value, f.getNow(null));
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- try {
- assertEquals(value, f.get());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- assertTrue(f.isDone());
- assertFalse(f.isCancelled());
- assertFalse(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed normally]"));
- }
-
- /**
- * Returns the "raw" internal exceptional completion of f,
- * without any additional wrapping with CompletionException.
- */
- <U> Throwable exceptionalCompletion(CompletableFuture<U> f) {
- // handle (and whenComplete) can distinguish between "direct"
- // and "wrapped" exceptional completion
- return f.handle((U u, Throwable t) -> t).join();
- }
-
- void checkCompletedExceptionally(CompletableFuture<?> f,
- boolean wrapped,
- Consumer<Throwable> checker) {
- Throwable cause = exceptionalCompletion(f);
- if (wrapped) {
- assertTrue(cause instanceof CompletionException);
- cause = cause.getCause();
- }
- checker.accept(cause);
-
- long startTime = System.nanoTime();
- try {
- f.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(cause, success.getCause());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
-
- try {
- f.join();
- shouldThrow();
- } catch (CompletionException success) {
- assertSame(cause, success.getCause());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- f.getNow(null);
- shouldThrow();
- } catch (CompletionException success) {
- assertSame(cause, success.getCause());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- f.get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(cause, success.getCause());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- assertFalse(f.isCancelled());
- assertTrue(f.isDone());
- assertTrue(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
- }
-
- void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
- checkCompletedExceptionally(f, true,
- (t) -> assertTrue(t instanceof CFException));
- }
-
- void checkCompletedWithWrappedCancellationException(CompletableFuture<?> f) {
- checkCompletedExceptionally(f, true,
- (t) -> assertTrue(t instanceof CancellationException));
- }
-
- void checkCompletedWithTimeoutException(CompletableFuture<?> f) {
- checkCompletedExceptionally(f, false,
- (t) -> assertTrue(t instanceof TimeoutException));
- }
-
- void checkCompletedWithWrappedException(CompletableFuture<?> f,
- Throwable ex) {
- checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex));
- }
-
- void checkCompletedExceptionally(CompletableFuture<?> f, Throwable ex) {
- checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex));
- }
-
- void checkCancelled(CompletableFuture<?> f) {
- long startTime = System.nanoTime();
- try {
- f.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (CancellationException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
-
- try {
- f.join();
- shouldThrow();
- } catch (CancellationException success) {}
- try {
- f.getNow(null);
- shouldThrow();
- } catch (CancellationException success) {}
- try {
- f.get();
- shouldThrow();
- } catch (CancellationException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- assertTrue(exceptionalCompletion(f) instanceof CancellationException);
-
- assertTrue(f.isDone());
- assertTrue(f.isCompletedExceptionally());
- assertTrue(f.isCancelled());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
- }
-
- /**
- * A newly constructed CompletableFuture is incomplete, as indicated
- * by methods isDone, isCancelled, and getNow
- */
- public void testConstructor() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- checkIncomplete(f);
- }
-
- /**
- * complete completes normally, as indicated by methods isDone,
- * isCancelled, join, get, and getNow
- */
- public void testComplete() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- checkIncomplete(f);
- assertTrue(f.complete(v1));
- assertFalse(f.complete(v1));
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * completeExceptionally completes exceptionally, as indicated by
- * methods isDone, isCancelled, join, get, and getNow
- */
- public void testCompleteExceptionally() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CFException ex = new CFException();
- checkIncomplete(f);
- f.completeExceptionally(ex);
- checkCompletedExceptionally(f, ex);
- }
-
- /**
- * cancel completes exceptionally and reports cancelled, as indicated by
- * methods isDone, isCancelled, join, get, and getNow
- */
- public void testCancel() {
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- checkIncomplete(f);
- assertTrue(f.cancel(mayInterruptIfRunning));
- assertTrue(f.cancel(mayInterruptIfRunning));
- assertTrue(f.cancel(!mayInterruptIfRunning));
- checkCancelled(f);
- }}
-
- /**
- * obtrudeValue forces completion with given value
- */
- public void testObtrudeValue() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- checkIncomplete(f);
- assertTrue(f.complete(one));
- checkCompletedNormally(f, one);
- f.obtrudeValue(three);
- checkCompletedNormally(f, three);
- f.obtrudeValue(two);
- checkCompletedNormally(f, two);
- f = new CompletableFuture<>();
- f.obtrudeValue(three);
- checkCompletedNormally(f, three);
- f.obtrudeValue(null);
- checkCompletedNormally(f, null);
- f = new CompletableFuture<>();
- f.completeExceptionally(new CFException());
- f.obtrudeValue(four);
- checkCompletedNormally(f, four);
- }
-
- /**
- * obtrudeException forces completion with given exception
- */
- public void testObtrudeException() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CFException ex;
- CompletableFuture<Integer> f;
-
- f = new CompletableFuture<>();
- assertTrue(f.complete(v1));
- for (int i = 0; i < 2; i++) {
- f.obtrudeException(ex = new CFException());
- checkCompletedExceptionally(f, ex);
- }
-
- f = new CompletableFuture<>();
- for (int i = 0; i < 2; i++) {
- f.obtrudeException(ex = new CFException());
- checkCompletedExceptionally(f, ex);
- }
-
- f = new CompletableFuture<>();
- f.completeExceptionally(ex = new CFException());
- f.obtrudeValue(v1);
- checkCompletedNormally(f, v1);
- f.obtrudeException(ex = new CFException());
- checkCompletedExceptionally(f, ex);
- f.completeExceptionally(new CFException());
- checkCompletedExceptionally(f, ex);
- assertFalse(f.complete(v1));
- checkCompletedExceptionally(f, ex);
- }}
-
- /**
- * getNumberOfDependents returns number of dependent tasks
- */
- public void testGetNumberOfDependents() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- assertEquals(0, f.getNumberOfDependents());
- final CompletableFuture<Void> g = m.thenRun(f, new Noop(m));
- assertEquals(1, f.getNumberOfDependents());
- assertEquals(0, g.getNumberOfDependents());
- final CompletableFuture<Void> h = m.thenRun(f, new Noop(m));
- assertEquals(2, f.getNumberOfDependents());
- assertEquals(0, h.getNumberOfDependents());
- assertTrue(f.complete(v1));
- checkCompletedNormally(g, null);
- checkCompletedNormally(h, null);
- assertEquals(0, f.getNumberOfDependents());
- assertEquals(0, g.getNumberOfDependents());
- assertEquals(0, h.getNumberOfDependents());
- }}
-
- /**
- * toString indicates current completion state
- */
- public void testToString() {
- CompletableFuture<String> f;
-
- f = new CompletableFuture<String>();
- assertTrue(f.toString().contains("[Not completed]"));
-
- assertTrue(f.complete("foo"));
- assertTrue(f.toString().contains("[Completed normally]"));
-
- f = new CompletableFuture<String>();
- assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
- 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]"));
- }
- }
-
- /**
- * completedFuture returns a completed CompletableFuture with given value
- */
- public void testCompletedFuture() {
- CompletableFuture<String> f = CompletableFuture.completedFuture("test");
- checkCompletedNormally(f, "test");
- }
-
- abstract class CheckedAction {
- int invocationCount = 0;
- final ExecutionMode m;
- CheckedAction(ExecutionMode m) { this.m = m; }
- void invoked() {
- m.checkExecutionMode();
- assertEquals(0, invocationCount++);
- }
- void assertNotInvoked() { assertEquals(0, invocationCount); }
- void assertInvoked() { assertEquals(1, invocationCount); }
- }
-
- abstract class CheckedIntegerAction extends CheckedAction {
- Integer value;
- CheckedIntegerAction(ExecutionMode m) { super(m); }
- void assertValue(Integer expected) {
- assertInvoked();
- assertEquals(expected, value);
- }
- }
-
- class IntegerSupplier extends CheckedAction
- implements Supplier<Integer>
- {
- final Integer value;
- IntegerSupplier(ExecutionMode m, Integer value) {
- super(m);
- this.value = value;
- }
- public Integer get() {
- invoked();
- return value;
- }
- }
-
- // A function that handles and produces null values as well.
- static Integer inc(Integer x) {
- return (x == null) ? null : x + 1;
- }
-
- class NoopConsumer extends CheckedIntegerAction
- implements Consumer<Integer>
- {
- NoopConsumer(ExecutionMode m) { super(m); }
- public void accept(Integer x) {
- invoked();
- value = x;
- }
- }
-
- class IncFunction extends CheckedIntegerAction
- implements Function<Integer,Integer>
- {
- IncFunction(ExecutionMode m) { super(m); }
- public Integer apply(Integer x) {
- invoked();
- return value = inc(x);
- }
- }
-
- // Choose non-commutative actions for better coverage
- // A non-commutative function that handles and produces null values as well.
- static Integer subtract(Integer x, Integer y) {
- return (x == null && y == null) ? null :
- ((x == null) ? 42 : x.intValue())
- - ((y == null) ? 99 : y.intValue());
- }
-
- class SubtractAction extends CheckedIntegerAction
- implements BiConsumer<Integer, Integer>
- {
- SubtractAction(ExecutionMode m) { super(m); }
- public void accept(Integer x, Integer y) {
- invoked();
- value = subtract(x, y);
- }
- }
-
- class SubtractFunction extends CheckedIntegerAction
- implements BiFunction<Integer, Integer, Integer>
- {
- SubtractFunction(ExecutionMode m) { super(m); }
- public Integer apply(Integer x, Integer y) {
- invoked();
- return value = subtract(x, y);
- }
- }
-
- class Noop extends CheckedAction implements Runnable {
- Noop(ExecutionMode m) { super(m); }
- public void run() {
- invoked();
- }
- }
-
- class FailingSupplier extends CheckedAction
- implements Supplier<Integer>
- {
- FailingSupplier(ExecutionMode m) { super(m); }
- public Integer get() {
- invoked();
- throw new CFException();
- }
- }
-
- class FailingConsumer extends CheckedIntegerAction
- implements Consumer<Integer>
- {
- FailingConsumer(ExecutionMode m) { super(m); }
- public void accept(Integer x) {
- invoked();
- value = x;
- throw new CFException();
- }
- }
-
- class FailingBiConsumer extends CheckedIntegerAction
- implements BiConsumer<Integer, Integer>
- {
- FailingBiConsumer(ExecutionMode m) { super(m); }
- public void accept(Integer x, Integer y) {
- invoked();
- value = subtract(x, y);
- throw new CFException();
- }
- }
-
- class FailingFunction extends CheckedIntegerAction
- implements Function<Integer, Integer>
- {
- FailingFunction(ExecutionMode m) { super(m); }
- public Integer apply(Integer x) {
- invoked();
- value = x;
- throw new CFException();
- }
- }
-
- class FailingBiFunction extends CheckedIntegerAction
- implements BiFunction<Integer, Integer, Integer>
- {
- FailingBiFunction(ExecutionMode m) { super(m); }
- public Integer apply(Integer x, Integer y) {
- invoked();
- value = subtract(x, y);
- throw new CFException();
- }
- }
-
- class FailingRunnable extends CheckedAction implements Runnable {
- FailingRunnable(ExecutionMode m) { super(m); }
- public void run() {
- invoked();
- throw new CFException();
- }
- }
-
- class CompletableFutureInc extends CheckedIntegerAction
- implements Function<Integer, CompletableFuture<Integer>>
- {
- CompletableFutureInc(ExecutionMode m) { super(m); }
- public CompletableFuture<Integer> apply(Integer x) {
- invoked();
- value = x;
- CompletableFuture<Integer> f = new CompletableFuture<>();
- assertTrue(f.complete(inc(x)));
- return f;
- }
- }
-
- class FailingCompletableFutureFunction extends CheckedIntegerAction
- implements Function<Integer, CompletableFuture<Integer>>
- {
- FailingCompletableFutureFunction(ExecutionMode m) { super(m); }
- public CompletableFuture<Integer> apply(Integer x) {
- invoked();
- value = x;
- throw new CFException();
- }
- }
-
- // Used for explicit executor tests
- static final class ThreadExecutor implements Executor {
- final AtomicInteger count = new AtomicInteger(0);
- static final ThreadGroup tg = new ThreadGroup("ThreadExecutor");
- static boolean startedCurrentThread() {
- return Thread.currentThread().getThreadGroup() == tg;
- }
-
- public void execute(Runnable r) {
- count.getAndIncrement();
- new Thread(tg, r).start();
- }
- }
-
- static final boolean defaultExecutorIsCommonPool
- = ForkJoinPool.getCommonPoolParallelism() > 1;
-
- /**
- * Permits the testing of parallel code for the 3 different
- * execution modes without copy/pasting all the test methods.
- */
- enum ExecutionMode {
- SYNC {
- public void checkExecutionMode() {
- assertFalse(ThreadExecutor.startedCurrentThread());
- assertNull(ForkJoinTask.getPool());
- }
- public CompletableFuture<Void> runAsync(Runnable a) {
- throw new UnsupportedOperationException();
- }
- public <U> CompletableFuture<U> supplyAsync(Supplier<U> a) {
- throw new UnsupportedOperationException();
- }
- public <T> CompletableFuture<Void> thenRun
- (CompletableFuture<T> f, Runnable a) {
- return f.thenRun(a);
- }
- public <T> CompletableFuture<Void> thenAccept
- (CompletableFuture<T> f, Consumer<? super T> a) {
- return f.thenAccept(a);
- }
- public <T,U> CompletableFuture<U> thenApply
- (CompletableFuture<T> f, Function<? super T,U> a) {
- return f.thenApply(a);
- }
- public <T,U> CompletableFuture<U> thenCompose
- (CompletableFuture<T> f,
- Function<? super T,? extends CompletionStage<U>> a) {
- return f.thenCompose(a);
- }
- public <T,U> CompletableFuture<U> handle
- (CompletableFuture<T> f,
- BiFunction<? super T,Throwable,? extends U> a) {
- return f.handle(a);
- }
- public <T> CompletableFuture<T> whenComplete
- (CompletableFuture<T> f,
- BiConsumer<? super T,? super Throwable> a) {
- return f.whenComplete(a);
- }
- public <T,U> CompletableFuture<Void> runAfterBoth
- (CompletableFuture<T> f, CompletableFuture<U> g, Runnable a) {
- return f.runAfterBoth(g, a);
- }
- public <T,U> CompletableFuture<Void> thenAcceptBoth
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiConsumer<? super T,? super U> a) {
- return f.thenAcceptBoth(g, a);
- }
- public <T,U,V> CompletableFuture<V> thenCombine
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiFunction<? super T,? super U,? extends V> a) {
- return f.thenCombine(g, a);
- }
- public <T> CompletableFuture<Void> runAfterEither
- (CompletableFuture<T> f,
- CompletionStage<?> g,
- java.lang.Runnable a) {
- return f.runAfterEither(g, a);
- }
- public <T> CompletableFuture<Void> acceptEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Consumer<? super T> a) {
- return f.acceptEither(g, a);
- }
- public <T,U> CompletableFuture<U> applyToEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Function<? super T,U> a) {
- return f.applyToEither(g, a);
- }
- },
-
- ASYNC {
- public void checkExecutionMode() {
- assertEquals(defaultExecutorIsCommonPool,
- (ForkJoinPool.commonPool() == ForkJoinTask.getPool()));
- }
- public CompletableFuture<Void> runAsync(Runnable a) {
- return CompletableFuture.runAsync(a);
- }
- public <U> CompletableFuture<U> supplyAsync(Supplier<U> a) {
- return CompletableFuture.supplyAsync(a);
- }
- public <T> CompletableFuture<Void> thenRun
- (CompletableFuture<T> f, Runnable a) {
- return f.thenRunAsync(a);
- }
- public <T> CompletableFuture<Void> thenAccept
- (CompletableFuture<T> f, Consumer<? super T> a) {
- return f.thenAcceptAsync(a);
- }
- public <T,U> CompletableFuture<U> thenApply
- (CompletableFuture<T> f, Function<? super T,U> a) {
- return f.thenApplyAsync(a);
- }
- public <T,U> CompletableFuture<U> thenCompose
- (CompletableFuture<T> f,
- Function<? super T,? extends CompletionStage<U>> a) {
- return f.thenComposeAsync(a);
- }
- public <T,U> CompletableFuture<U> handle
- (CompletableFuture<T> f,
- BiFunction<? super T,Throwable,? extends U> a) {
- return f.handleAsync(a);
- }
- public <T> CompletableFuture<T> whenComplete
- (CompletableFuture<T> f,
- BiConsumer<? super T,? super Throwable> a) {
- return f.whenCompleteAsync(a);
- }
- public <T,U> CompletableFuture<Void> runAfterBoth
- (CompletableFuture<T> f, CompletableFuture<U> g, Runnable a) {
- return f.runAfterBothAsync(g, a);
- }
- public <T,U> CompletableFuture<Void> thenAcceptBoth
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiConsumer<? super T,? super U> a) {
- return f.thenAcceptBothAsync(g, a);
- }
- public <T,U,V> CompletableFuture<V> thenCombine
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiFunction<? super T,? super U,? extends V> a) {
- return f.thenCombineAsync(g, a);
- }
- public <T> CompletableFuture<Void> runAfterEither
- (CompletableFuture<T> f,
- CompletionStage<?> g,
- java.lang.Runnable a) {
- return f.runAfterEitherAsync(g, a);
- }
- public <T> CompletableFuture<Void> acceptEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Consumer<? super T> a) {
- return f.acceptEitherAsync(g, a);
- }
- public <T,U> CompletableFuture<U> applyToEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Function<? super T,U> a) {
- return f.applyToEitherAsync(g, a);
- }
- },
-
- EXECUTOR {
- public void checkExecutionMode() {
- assertTrue(ThreadExecutor.startedCurrentThread());
- }
- public CompletableFuture<Void> runAsync(Runnable a) {
- return CompletableFuture.runAsync(a, new ThreadExecutor());
- }
- public <U> CompletableFuture<U> supplyAsync(Supplier<U> a) {
- return CompletableFuture.supplyAsync(a, new ThreadExecutor());
- }
- public <T> CompletableFuture<Void> thenRun
- (CompletableFuture<T> f, Runnable a) {
- return f.thenRunAsync(a, new ThreadExecutor());
- }
- public <T> CompletableFuture<Void> thenAccept
- (CompletableFuture<T> f, Consumer<? super T> a) {
- return f.thenAcceptAsync(a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<U> thenApply
- (CompletableFuture<T> f, Function<? super T,U> a) {
- return f.thenApplyAsync(a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<U> thenCompose
- (CompletableFuture<T> f,
- Function<? super T,? extends CompletionStage<U>> a) {
- return f.thenComposeAsync(a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<U> handle
- (CompletableFuture<T> f,
- BiFunction<? super T,Throwable,? extends U> a) {
- return f.handleAsync(a, new ThreadExecutor());
- }
- public <T> CompletableFuture<T> whenComplete
- (CompletableFuture<T> f,
- BiConsumer<? super T,? super Throwable> a) {
- return f.whenCompleteAsync(a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<Void> runAfterBoth
- (CompletableFuture<T> f, CompletableFuture<U> g, Runnable a) {
- return f.runAfterBothAsync(g, a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<Void> thenAcceptBoth
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiConsumer<? super T,? super U> a) {
- return f.thenAcceptBothAsync(g, a, new ThreadExecutor());
- }
- public <T,U,V> CompletableFuture<V> thenCombine
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiFunction<? super T,? super U,? extends V> a) {
- return f.thenCombineAsync(g, a, new ThreadExecutor());
- }
- public <T> CompletableFuture<Void> runAfterEither
- (CompletableFuture<T> f,
- CompletionStage<?> g,
- java.lang.Runnable a) {
- return f.runAfterEitherAsync(g, a, new ThreadExecutor());
- }
- public <T> CompletableFuture<Void> acceptEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Consumer<? super T> a) {
- return f.acceptEitherAsync(g, a, new ThreadExecutor());
- }
- public <T,U> CompletableFuture<U> applyToEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Function<? super T,U> a) {
- return f.applyToEitherAsync(g, a, new ThreadExecutor());
- }
- };
-
- public abstract void checkExecutionMode();
- public abstract CompletableFuture<Void> runAsync(Runnable a);
- public abstract <U> CompletableFuture<U> supplyAsync(Supplier<U> a);
- public abstract <T> CompletableFuture<Void> thenRun
- (CompletableFuture<T> f, Runnable a);
- public abstract <T> CompletableFuture<Void> thenAccept
- (CompletableFuture<T> f, Consumer<? super T> a);
- public abstract <T,U> CompletableFuture<U> thenApply
- (CompletableFuture<T> f, Function<? super T,U> a);
- public abstract <T,U> CompletableFuture<U> thenCompose
- (CompletableFuture<T> f,
- Function<? super T,? extends CompletionStage<U>> a);
- public abstract <T,U> CompletableFuture<U> handle
- (CompletableFuture<T> f,
- BiFunction<? super T,Throwable,? extends U> a);
- public abstract <T> CompletableFuture<T> whenComplete
- (CompletableFuture<T> f,
- BiConsumer<? super T,? super Throwable> a);
- public abstract <T,U> CompletableFuture<Void> runAfterBoth
- (CompletableFuture<T> f, CompletableFuture<U> g, Runnable a);
- public abstract <T,U> CompletableFuture<Void> thenAcceptBoth
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiConsumer<? super T,? super U> a);
- public abstract <T,U,V> CompletableFuture<V> thenCombine
- (CompletableFuture<T> f,
- CompletionStage<? extends U> g,
- BiFunction<? super T,? super U,? extends V> a);
- public abstract <T> CompletableFuture<Void> runAfterEither
- (CompletableFuture<T> f,
- CompletionStage<?> g,
- java.lang.Runnable a);
- public abstract <T> CompletableFuture<Void> acceptEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Consumer<? super T> a);
- public abstract <T,U> CompletableFuture<U> applyToEither
- (CompletableFuture<T> f,
- CompletionStage<? extends T> g,
- Function<? super T,U> a);
- }
-
- /**
- * exceptionally action is not invoked when source completes
- * normally, and source result is propagated
- */
- public void testExceptionally_normalCompletion() {
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = f.exceptionally
- ((Throwable t) -> {
- a.getAndIncrement();
- threadFail("should not be called");
- return null; // unreached
- });
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedNormally(g, v1);
- checkCompletedNormally(f, v1);
- assertEquals(0, a.get());
- }}
-
- /**
- * exceptionally action completes with function value on source
- * exception
- */
- public void testExceptionally_exceptionalCompletion() {
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) f.completeExceptionally(ex);
- final CompletableFuture<Integer> g = f.exceptionally
- ((Throwable t) -> {
- ExecutionMode.SYNC.checkExecutionMode();
- threadAssertSame(t, ex);
- a.getAndIncrement();
- return v1;
- });
- if (createIncomplete) f.completeExceptionally(ex);
-
- checkCompletedNormally(g, v1);
- assertEquals(1, a.get());
- }}
-
- /**
- * If an "exceptionally action" throws an exception, it completes
- * exceptionally with that exception
- */
- public void testExceptionally_exceptionalCompletionActionFailed() {
- for (boolean createIncomplete : new boolean[] { true, false })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex1 = new CFException();
- final CFException ex2 = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) f.completeExceptionally(ex1);
- final CompletableFuture<Integer> g = f.exceptionally
- ((Throwable t) -> {
- ExecutionMode.SYNC.checkExecutionMode();
- threadAssertSame(t, ex1);
- a.getAndIncrement();
- throw ex2;
- });
- if (createIncomplete) f.completeExceptionally(ex1);
-
- checkCompletedWithWrappedException(g, ex2);
- checkCompletedExceptionally(f, ex1);
- assertEquals(1, a.get());
- }}
-
- /**
- * whenComplete action executes on normal completion, propagating
- * source result.
- */
- public void testWhenComplete_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.whenComplete
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertSame(result, v1);
- threadAssertNull(t);
- a.getAndIncrement();
- });
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedNormally(g, v1);
- checkCompletedNormally(f, v1);
- assertEquals(1, a.get());
- }}
-
- /**
- * whenComplete action executes on exceptional completion, propagating
- * source result.
- */
- public void testWhenComplete_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) f.completeExceptionally(ex);
- final CompletableFuture<Integer> g = m.whenComplete
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertNull(result);
- threadAssertSame(t, ex);
- a.getAndIncrement();
- });
- if (createIncomplete) f.completeExceptionally(ex);
-
- checkCompletedWithWrappedException(g, ex);
- checkCompletedExceptionally(f, ex);
- assertEquals(1, a.get());
- }}
-
- /**
- * whenComplete action executes on cancelled source, propagating
- * CancellationException.
- */
- public void testWhenComplete_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean createIncomplete : new boolean[] { true, false })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Integer> g = m.whenComplete
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertNull(result);
- threadAssertTrue(t instanceof CancellationException);
- a.getAndIncrement();
- });
- if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
-
- checkCompletedWithWrappedCancellationException(g);
- checkCancelled(f);
- assertEquals(1, a.get());
- }}
-
- /**
- * If a whenComplete action throws an exception when triggered by
- * a normal completion, it completes exceptionally
- */
- public void testWhenComplete_sourceCompletedNormallyActionFailed() {
- for (boolean createIncomplete : new boolean[] { true, false })
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.whenComplete
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertSame(result, v1);
- threadAssertNull(t);
- a.getAndIncrement();
- throw ex;
- });
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedWithWrappedException(g, ex);
- checkCompletedNormally(f, v1);
- assertEquals(1, a.get());
- }}
-
- /**
- * If a whenComplete action throws an exception when triggered by
- * a source completion that also throws an exception, the source
- * exception takes precedence (unlike handle)
- */
- public void testWhenComplete_sourceFailedActionFailed() {
- for (boolean createIncomplete : new boolean[] { true, false })
- for (ExecutionMode m : ExecutionMode.values())
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex1 = new CFException();
- final CFException ex2 = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
-
- if (!createIncomplete) f.completeExceptionally(ex1);
- final CompletableFuture<Integer> g = m.whenComplete
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertSame(t, ex1);
- threadAssertNull(result);
- a.getAndIncrement();
- throw ex2;
- });
- if (createIncomplete) f.completeExceptionally(ex1);
-
- checkCompletedWithWrappedException(g, ex1);
- checkCompletedExceptionally(f, ex1);
- if (testImplementationDetails) {
- assertEquals(1, ex1.getSuppressed().length);
- assertSame(ex2, ex1.getSuppressed()[0]);
- }
- assertEquals(1, a.get());
- }}
-
- /**
- * handle action completes normally with function value on normal
- * completion of source
- */
- public void testHandle_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final AtomicInteger a = new AtomicInteger(0);
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.handle
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertSame(result, v1);
- threadAssertNull(t);
- a.getAndIncrement();
- return inc(v1);
- });
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedNormally(g, inc(v1));
- checkCompletedNormally(f, v1);
- assertEquals(1, a.get());
- }}
-
- /**
- * handle action completes normally with function value on
- * exceptional completion of source
- */
- public void testHandle_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex = new CFException();
- if (!createIncomplete) f.completeExceptionally(ex);
- final CompletableFuture<Integer> g = m.handle
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertNull(result);
- threadAssertSame(t, ex);
- a.getAndIncrement();
- return v1;
- });
- if (createIncomplete) f.completeExceptionally(ex);
-
- checkCompletedNormally(g, v1);
- checkCompletedExceptionally(f, ex);
- assertEquals(1, a.get());
- }}
-
- /**
- * handle action completes normally with function value on
- * cancelled source
- */
- public void testHandle_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final AtomicInteger a = new AtomicInteger(0);
- if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Integer> g = m.handle
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertNull(result);
- threadAssertTrue(t instanceof CancellationException);
- a.getAndIncrement();
- return v1;
- });
- if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
-
- checkCompletedNormally(g, v1);
- checkCancelled(f);
- assertEquals(1, a.get());
- }}
-
- /**
- * If a "handle action" throws an exception when triggered by
- * a normal completion, it completes exceptionally
- */
- public void testHandle_sourceCompletedNormallyActionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex = new CFException();
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.handle
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertSame(result, v1);
- threadAssertNull(t);
- a.getAndIncrement();
- throw ex;
- });
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedWithWrappedException(g, ex);
- checkCompletedNormally(f, v1);
- assertEquals(1, a.get());
- }}
-
- /**
- * If a "handle action" throws an exception when triggered by
- * a source completion that also throws an exception, the action
- * exception takes precedence (unlike whenComplete)
- */
- public void testHandle_sourceFailedActionFailed() {
- for (boolean createIncomplete : new boolean[] { true, false })
- for (ExecutionMode m : ExecutionMode.values())
- {
- final AtomicInteger a = new AtomicInteger(0);
- final CFException ex1 = new CFException();
- final CFException ex2 = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
-
- if (!createIncomplete) f.completeExceptionally(ex1);
- final CompletableFuture<Integer> g = m.handle
- (f,
- (Integer result, Throwable t) -> {
- m.checkExecutionMode();
- threadAssertNull(result);
- threadAssertSame(ex1, t);
- a.getAndIncrement();
- throw ex2;
- });
- if (createIncomplete) f.completeExceptionally(ex1);
-
- checkCompletedWithWrappedException(g, ex2);
- checkCompletedExceptionally(f, ex1);
- assertEquals(1, a.get());
- }}
-
- /**
- * runAsync completes after running Runnable
- */
- public void testRunAsync_normalCompletion() {
- ExecutionMode[] executionModes = {
- ExecutionMode.ASYNC,
- ExecutionMode.EXECUTOR,
- };
- for (ExecutionMode m : executionModes)
- {
- final Noop r = new Noop(m);
- final CompletableFuture<Void> f = m.runAsync(r);
- assertNull(f.join());
- checkCompletedNormally(f, null);
- r.assertInvoked();
- }}
-
- /**
- * failing runAsync completes exceptionally after running Runnable
- */
- public void testRunAsync_exceptionalCompletion() {
- ExecutionMode[] executionModes = {
- ExecutionMode.ASYNC,
- ExecutionMode.EXECUTOR,
- };
- for (ExecutionMode m : executionModes)
- {
- final FailingRunnable r = new FailingRunnable(m);
- final CompletableFuture<Void> f = m.runAsync(r);
- checkCompletedWithWrappedCFException(f);
- r.assertInvoked();
- }}
-
- /**
- * supplyAsync completes with result of supplier
- */
- public void testSupplyAsync_normalCompletion() {
- ExecutionMode[] executionModes = {
- ExecutionMode.ASYNC,
- ExecutionMode.EXECUTOR,
- };
- for (ExecutionMode m : executionModes)
- for (Integer v1 : new Integer[] { 1, null })
- {
- final IntegerSupplier r = new IntegerSupplier(m, v1);
- final CompletableFuture<Integer> f = m.supplyAsync(r);
- assertSame(v1, f.join());
- checkCompletedNormally(f, v1);
- r.assertInvoked();
- }}
-
- /**
- * Failing supplyAsync completes exceptionally
- */
- public void testSupplyAsync_exceptionalCompletion() {
- ExecutionMode[] executionModes = {
- ExecutionMode.ASYNC,
- ExecutionMode.EXECUTOR,
- };
- for (ExecutionMode m : executionModes)
- {
- FailingSupplier r = new FailingSupplier(m);
- CompletableFuture<Integer> f = m.supplyAsync(r);
- checkCompletedWithWrappedCFException(f);
- r.assertInvoked();
- }}
-
- // seq completion methods
-
- /**
- * thenRun result completes normally after normal completion of source
- */
- public void testThenRun_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.thenRun(f, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, f, rs[1]);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, f, rs[2]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(f.complete(v1));
- final CompletableFuture<Void> h3 = m.thenRun(f, rs[3]);
- final CompletableFuture<Void> h4 = m.runAfterBoth(f, f, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(f, f, rs[5]);
-
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- checkCompletedNormally(h4, null);
- checkCompletedNormally(h5, null);
- checkCompletedNormally(f, v1);
- for (Noop r : rs) r.assertInvoked();
- }}
-
- /**
- * thenRun result completes exceptionally after exceptional
- * completion of source
- */
- public void testThenRun_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- {
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.thenRun(f, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, f, rs[1]);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, f, rs[2]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(f.completeExceptionally(ex));
- final CompletableFuture<Void> h3 = m.thenRun(f, rs[3]);
- final CompletableFuture<Void> h4 = m.runAfterBoth(f, f, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(f, f, rs[5]);
-
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedWithWrappedException(h4, ex);
- checkCompletedWithWrappedException(h5, ex);
- checkCompletedExceptionally(f, ex);
- for (Noop r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenRun result completes exceptionally if source cancelled
- */
- public void testThenRun_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.thenRun(f, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, f, rs[1]);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, f, rs[2]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Void> h3 = m.thenRun(f, rs[3]);
- final CompletableFuture<Void> h4 = m.runAfterBoth(f, f, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(f, f, rs[5]);
-
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- checkCompletedWithWrappedCancellationException(h4);
- checkCompletedWithWrappedCancellationException(h5);
- checkCancelled(f);
- for (Noop r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenRun result completes exceptionally if action does
- */
- public void testThenRun_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final FailingRunnable[] rs = new FailingRunnable[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingRunnable(m);
-
- final CompletableFuture<Void> h0 = m.thenRun(f, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, f, rs[1]);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, f, rs[2]);
- assertTrue(f.complete(v1));
- final CompletableFuture<Void> h3 = m.thenRun(f, rs[3]);
- final CompletableFuture<Void> h4 = m.runAfterBoth(f, f, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(f, f, rs[5]);
-
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- checkCompletedWithWrappedCFException(h4);
- checkCompletedWithWrappedCFException(h5);
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * thenApply result completes normally after normal completion of source
- */
- public void testThenApply_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.thenApply(f, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(f, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- assertTrue(f.complete(v1));
- final CompletableFuture<Integer> h2 = m.thenApply(f, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(f, f, rs[3]);
-
- checkCompletedNormally(h0, inc(v1));
- checkCompletedNormally(h1, inc(v1));
- checkCompletedNormally(h2, inc(v1));
- checkCompletedNormally(h3, inc(v1));
- checkCompletedNormally(f, v1);
- for (IncFunction r : rs) r.assertValue(inc(v1));
- }}
-
- /**
- * thenApply result completes exceptionally after exceptional
- * completion of source
- */
- public void testThenApply_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- {
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.thenApply(f, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(f, f, rs[1]);
- assertTrue(f.completeExceptionally(ex));
- final CompletableFuture<Integer> h2 = m.thenApply(f, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(f, f, rs[3]);
-
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedExceptionally(f, ex);
- for (IncFunction r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenApply result completes exceptionally if source cancelled
- */
- public void testThenApply_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.thenApply(f, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(f, f, rs[1]);
- assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Integer> h2 = m.thenApply(f, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(f, f, rs[3]);
-
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- checkCancelled(f);
- for (IncFunction r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenApply result completes exceptionally if action does
- */
- public void testThenApply_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final FailingFunction[] rs = new FailingFunction[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingFunction(m);
-
- final CompletableFuture<Integer> h0 = m.thenApply(f, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(f, f, rs[1]);
- assertTrue(f.complete(v1));
- final CompletableFuture<Integer> h2 = m.thenApply(f, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(f, f, rs[3]);
-
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * thenAccept result completes normally after normal completion of source
- */
- public void testThenAccept_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final NoopConsumer[] rs = new NoopConsumer[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.thenAccept(f, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(f, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- assertTrue(f.complete(v1));
- final CompletableFuture<Void> h2 = m.thenAccept(f, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(f, f, rs[3]);
-
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- checkCompletedNormally(f, v1);
- for (NoopConsumer r : rs) r.assertValue(v1);
- }}
-
- /**
- * thenAccept result completes exceptionally after exceptional
- * completion of source
- */
- public void testThenAccept_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- {
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final NoopConsumer[] rs = new NoopConsumer[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.thenAccept(f, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(f, f, rs[1]);
- assertTrue(f.completeExceptionally(ex));
- final CompletableFuture<Void> h2 = m.thenAccept(f, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(f, f, rs[3]);
-
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedExceptionally(f, ex);
- for (NoopConsumer r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenAccept result completes exceptionally if source cancelled
- */
- public void testThenAccept_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final NoopConsumer[] rs = new NoopConsumer[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.thenAccept(f, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(f, f, rs[1]);
- assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Void> h2 = m.thenAccept(f, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(f, f, rs[3]);
-
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- checkCancelled(f);
- for (NoopConsumer r : rs) r.assertNotInvoked();
- }}
-
- /**
- * thenAccept result completes exceptionally if action does
- */
- public void testThenAccept_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final FailingConsumer[] rs = new FailingConsumer[4];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingConsumer(m);
-
- final CompletableFuture<Void> h0 = m.thenAccept(f, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(f, f, rs[1]);
- assertTrue(f.complete(v1));
- final CompletableFuture<Void> h2 = m.thenAccept(f, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(f, f, rs[3]);
-
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * thenCombine result completes normally after normal completion
- * of sources
- */
- public void testThenCombine_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final SubtractFunction[] rs = new SubtractFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new SubtractFunction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Integer> h0 = m.thenCombine(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.thenCombine(fst, fst, rs[1]);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Integer> h2 = m.thenCombine(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.thenCombine(fst, fst, rs[3]);
- checkIncomplete(h0); rs[0].assertNotInvoked();
- checkIncomplete(h2); rs[2].assertNotInvoked();
- checkCompletedNormally(h1, subtract(w1, w1));
- checkCompletedNormally(h3, subtract(w1, w1));
- rs[1].assertValue(subtract(w1, w1));
- rs[3].assertValue(subtract(w1, w1));
- assertTrue(snd.complete(w2));
- final CompletableFuture<Integer> h4 = m.thenCombine(f, g, rs[4]);
-
- checkCompletedNormally(h0, subtract(v1, v2));
- checkCompletedNormally(h2, subtract(v1, v2));
- checkCompletedNormally(h4, subtract(v1, v2));
- rs[0].assertValue(subtract(v1, v2));
- rs[2].assertValue(subtract(v1, v2));
- rs[4].assertValue(subtract(v1, v2));
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * thenCombine result completes exceptionally after exceptional
- * completion of either source
- */
- public void testThenCombine_exceptionalCompletion() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final SubtractFunction r1 = new SubtractFunction(m);
- final SubtractFunction r2 = new SubtractFunction(m);
- final SubtractFunction r3 = new SubtractFunction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.completeExceptionally(ex) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.completeExceptionally(ex);
-
- final CompletableFuture<Integer> h1 = m.thenCombine(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Integer> h2 = m.thenCombine(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Integer> h3 = m.thenCombine(f, g, r3);
-
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCompletedExceptionally(failFirst ? fst : snd, ex);
- }}
-
- /**
- * thenCombine result completes exceptionally if either source cancelled
- */
- public void testThenCombine_sourceCancelled() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final SubtractFunction r1 = new SubtractFunction(m);
- final SubtractFunction r2 = new SubtractFunction(m);
- final SubtractFunction r3 = new SubtractFunction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.cancel(mayInterruptIfRunning) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.cancel(mayInterruptIfRunning);
-
- final CompletableFuture<Integer> h1 = m.thenCombine(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Integer> h2 = m.thenCombine(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Integer> h3 = m.thenCombine(f, g, r3);
-
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCancelled(failFirst ? fst : snd);
- }}
-
- /**
- * thenCombine result completes exceptionally if action does
- */
- public void testThenCombine_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingBiFunction r1 = new FailingBiFunction(m);
- final FailingBiFunction r2 = new FailingBiFunction(m);
- final FailingBiFunction r3 = new FailingBiFunction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Integer> h1 = m.thenCombine(f, g, r1);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Integer> h2 = m.thenCombine(f, g, r2);
- assertTrue(snd.complete(w2));
- final CompletableFuture<Integer> h3 = m.thenCombine(f, g, r3);
-
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- r1.assertInvoked();
- r2.assertInvoked();
- r3.assertInvoked();
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * thenAcceptBoth result completes normally after normal
- * completion of sources
- */
- public void testThenAcceptBoth_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final SubtractAction r1 = new SubtractAction(m);
- final SubtractAction r2 = new SubtractAction(m);
- final SubtractAction r3 = new SubtractAction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Void> h1 = m.thenAcceptBoth(f, g, r1);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Void> h2 = m.thenAcceptBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- assertTrue(snd.complete(w2));
- final CompletableFuture<Void> h3 = m.thenAcceptBoth(f, g, r3);
-
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- r1.assertValue(subtract(v1, v2));
- r2.assertValue(subtract(v1, v2));
- r3.assertValue(subtract(v1, v2));
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * thenAcceptBoth result completes exceptionally after exceptional
- * completion of either source
- */
- public void testThenAcceptBoth_exceptionalCompletion() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final SubtractAction r1 = new SubtractAction(m);
- final SubtractAction r2 = new SubtractAction(m);
- final SubtractAction r3 = new SubtractAction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.completeExceptionally(ex) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.completeExceptionally(ex);
-
- final CompletableFuture<Void> h1 = m.thenAcceptBoth(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Void> h2 = m.thenAcceptBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Void> h3 = m.thenAcceptBoth(f, g, r3);
-
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCompletedExceptionally(failFirst ? fst : snd, ex);
- }}
-
- /**
- * thenAcceptBoth result completes exceptionally if either source cancelled
- */
- public void testThenAcceptBoth_sourceCancelled() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final SubtractAction r1 = new SubtractAction(m);
- final SubtractAction r2 = new SubtractAction(m);
- final SubtractAction r3 = new SubtractAction(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.cancel(mayInterruptIfRunning) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.cancel(mayInterruptIfRunning);
-
- final CompletableFuture<Void> h1 = m.thenAcceptBoth(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Void> h2 = m.thenAcceptBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Void> h3 = m.thenAcceptBoth(f, g, r3);
-
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCancelled(failFirst ? fst : snd);
- }}
-
- /**
- * thenAcceptBoth result completes exceptionally if action does
- */
- public void testThenAcceptBoth_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingBiConsumer r1 = new FailingBiConsumer(m);
- final FailingBiConsumer r2 = new FailingBiConsumer(m);
- final FailingBiConsumer r3 = new FailingBiConsumer(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Void> h1 = m.thenAcceptBoth(f, g, r1);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Void> h2 = m.thenAcceptBoth(f, g, r2);
- assertTrue(snd.complete(w2));
- final CompletableFuture<Void> h3 = m.thenAcceptBoth(f, g, r3);
-
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- r1.assertInvoked();
- r2.assertInvoked();
- r3.assertInvoked();
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * runAfterBoth result completes normally after normal
- * completion of sources
- */
- public void testRunAfterBoth_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final Noop r1 = new Noop(m);
- final Noop r2 = new Noop(m);
- final Noop r3 = new Noop(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, g, r1);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Void> h2 = m.runAfterBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- assertTrue(snd.complete(w2));
- final CompletableFuture<Void> h3 = m.runAfterBoth(f, g, r3);
-
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- r1.assertInvoked();
- r2.assertInvoked();
- r3.assertInvoked();
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * runAfterBoth result completes exceptionally after exceptional
- * completion of either source
- */
- public void testRunAfterBoth_exceptionalCompletion() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final Noop r1 = new Noop(m);
- final Noop r2 = new Noop(m);
- final Noop r3 = new Noop(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.completeExceptionally(ex) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.completeExceptionally(ex);
-
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Void> h2 = m.runAfterBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Void> h3 = m.runAfterBoth(f, g, r3);
-
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCompletedExceptionally(failFirst ? fst : snd, ex);
- }}
-
- /**
- * runAfterBoth result completes exceptionally if either source cancelled
- */
- public void testRunAfterBoth_sourceCancelled() throws Throwable {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean fFirst : new boolean[] { true, false })
- for (boolean failFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final Noop r1 = new Noop(m);
- final Noop r2 = new Noop(m);
- final Noop r3 = new Noop(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Callable<Boolean> complete1 = failFirst ?
- () -> fst.cancel(mayInterruptIfRunning) :
- () -> fst.complete(v1);
- final Callable<Boolean> complete2 = failFirst ?
- () -> snd.complete(v1) :
- () -> snd.cancel(mayInterruptIfRunning);
-
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, g, r1);
- assertTrue(complete1.call());
- final CompletableFuture<Void> h2 = m.runAfterBoth(f, g, r2);
- checkIncomplete(h1);
- checkIncomplete(h2);
- assertTrue(complete2.call());
- final CompletableFuture<Void> h3 = m.runAfterBoth(f, g, r3);
-
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- r1.assertNotInvoked();
- r2.assertNotInvoked();
- r3.assertNotInvoked();
- checkCompletedNormally(failFirst ? snd : fst, v1);
- checkCancelled(failFirst ? fst : snd);
- }}
-
- /**
- * runAfterBoth result completes exceptionally if action does
- */
- public void testRunAfterBoth_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingRunnable r1 = new FailingRunnable(m);
- final FailingRunnable r2 = new FailingRunnable(m);
- final FailingRunnable r3 = new FailingRunnable(m);
-
- final CompletableFuture<Integer> fst = fFirst ? f : g;
- final CompletableFuture<Integer> snd = !fFirst ? f : g;
- final Integer w1 = fFirst ? v1 : v2;
- final Integer w2 = !fFirst ? v1 : v2;
-
- final CompletableFuture<Void> h1 = m.runAfterBoth(f, g, r1);
- assertTrue(fst.complete(w1));
- final CompletableFuture<Void> h2 = m.runAfterBoth(f, g, r2);
- assertTrue(snd.complete(w2));
- final CompletableFuture<Void> h3 = m.runAfterBoth(f, g, r3);
-
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- r1.assertInvoked();
- r2.assertInvoked();
- r3.assertInvoked();
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * applyToEither result completes normally after normal completion
- * of either source
- */
- public void testApplyToEither_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.complete(v1);
- checkCompletedNormally(h0, inc(v1));
- checkCompletedNormally(h1, inc(v1));
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
- checkCompletedNormally(h2, inc(v1));
- checkCompletedNormally(h3, inc(v1));
- g.complete(v2);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Integer> h4 = m.applyToEither(f, g, rs[4]);
- final CompletableFuture<Integer> h5 = m.applyToEither(g, f, rs[5]);
- rs[4].assertValue(h4.join());
- rs[5].assertValue(h5.join());
- assertTrue(Objects.equals(inc(v1), h4.join()) ||
- Objects.equals(inc(v2), h4.join()));
- assertTrue(Objects.equals(inc(v1), h5.join()) ||
- Objects.equals(inc(v2), h5.join()));
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- checkCompletedNormally(h0, inc(v1));
- checkCompletedNormally(h1, inc(v1));
- checkCompletedNormally(h2, inc(v1));
- checkCompletedNormally(h3, inc(v1));
- for (int i = 0; i < 4; i++) rs[i].assertValue(inc(v1));
- }}
-
- /**
- * applyToEither result completes exceptionally after exceptional
- * completion of either source
- */
- public void testApplyToEither_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final IncFunction[] rs = new IncFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.completeExceptionally(ex);
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- g.complete(v1);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Integer> h4 = m.applyToEither(f, g, rs[4]);
- final CompletableFuture<Integer> h5 = m.applyToEither(g, f, rs[5]);
- try {
- assertEquals(inc(v1), h4.join());
- rs[4].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h4, ex);
- rs[4].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h5.join());
- rs[5].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h5, ex);
- rs[5].assertNotInvoked();
- }
-
- checkCompletedExceptionally(f, ex);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedWithWrappedException(h4, ex);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- public void testApplyToEither_exceptionalCompletion2() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final IncFunction[] rs = new IncFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- assertTrue(fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
-
- // unspecified behavior - both source completions available
- try {
- assertEquals(inc(v1), h0.join());
- rs[0].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h0, ex);
- rs[0].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h1.join());
- rs[1].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h1, ex);
- rs[1].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h2.join());
- rs[2].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h2, ex);
- rs[2].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h3.join());
- rs[3].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h3, ex);
- rs[3].assertNotInvoked();
- }
-
- checkCompletedNormally(f, v1);
- checkCompletedExceptionally(g, ex);
- }}
-
- /**
- * applyToEither result completes exceptionally if either source cancelled
- */
- public void testApplyToEither_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.cancel(mayInterruptIfRunning);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- g.complete(v1);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Integer> h4 = m.applyToEither(f, g, rs[4]);
- final CompletableFuture<Integer> h5 = m.applyToEither(g, f, rs[5]);
- try {
- assertEquals(inc(v1), h4.join());
- rs[4].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h4);
- rs[4].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h5.join());
- rs[5].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h5);
- rs[5].assertNotInvoked();
- }
-
- checkCancelled(f);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- public void testApplyToEither_sourceCancelled2() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final IncFunction[] rs = new IncFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- assertTrue(fFirst ? f.complete(v1) : g.cancel(mayInterruptIfRunning));
- assertTrue(!fFirst ? f.complete(v1) : g.cancel(mayInterruptIfRunning));
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
-
- // unspecified behavior - both source completions available
- try {
- assertEquals(inc(v1), h0.join());
- rs[0].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h0);
- rs[0].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h1.join());
- rs[1].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h1);
- rs[1].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h2.join());
- rs[2].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h2);
- rs[2].assertNotInvoked();
- }
- try {
- assertEquals(inc(v1), h3.join());
- rs[3].assertValue(inc(v1));
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h3);
- rs[3].assertNotInvoked();
- }
-
- checkCompletedNormally(f, v1);
- checkCancelled(g);
- }}
-
- /**
- * applyToEither result completes exceptionally if action does
- */
- public void testApplyToEither_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingFunction[] rs = new FailingFunction[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingFunction(m);
-
- final CompletableFuture<Integer> h0 = m.applyToEither(f, g, rs[0]);
- final CompletableFuture<Integer> h1 = m.applyToEither(g, f, rs[1]);
- f.complete(v1);
- final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
- final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertValue(v1);
-
- g.complete(v2);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Integer> h4 = m.applyToEither(f, g, rs[4]);
- final CompletableFuture<Integer> h5 = m.applyToEither(g, f, rs[5]);
-
- checkCompletedWithWrappedCFException(h4);
- assertTrue(Objects.equals(v1, rs[4].value) ||
- Objects.equals(v2, rs[4].value));
- checkCompletedWithWrappedCFException(h5);
- assertTrue(Objects.equals(v1, rs[5].value) ||
- Objects.equals(v2, rs[5].value));
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * acceptEither result completes normally after normal completion
- * of either source
- */
- public void testAcceptEither_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final NoopConsumer[] rs = new NoopConsumer[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.acceptEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.complete(v1);
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- rs[0].assertValue(v1);
- rs[1].assertValue(v1);
- final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- rs[2].assertValue(v1);
- rs[3].assertValue(v1);
- g.complete(v2);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.acceptEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.acceptEither(g, f, rs[5]);
- checkCompletedNormally(h4, null);
- checkCompletedNormally(h5, null);
- assertTrue(Objects.equals(v1, rs[4].value) ||
- Objects.equals(v2, rs[4].value));
- assertTrue(Objects.equals(v1, rs[5].value) ||
- Objects.equals(v2, rs[5].value));
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- for (int i = 0; i < 4; i++) rs[i].assertValue(v1);
- }}
-
- /**
- * acceptEither result completes exceptionally after exceptional
- * completion of either source
- */
- public void testAcceptEither_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final NoopConsumer[] rs = new NoopConsumer[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.acceptEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.completeExceptionally(ex);
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
-
- g.complete(v1);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.acceptEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.acceptEither(g, f, rs[5]);
- try {
- assertNull(h4.join());
- rs[4].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h4, ex);
- rs[4].assertNotInvoked();
- }
- try {
- assertNull(h5.join());
- rs[5].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h5, ex);
- rs[5].assertNotInvoked();
- }
-
- checkCompletedExceptionally(f, ex);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedWithWrappedException(h4, ex);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- public void testAcceptEither_exceptionalCompletion2() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final NoopConsumer[] rs = new NoopConsumer[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.acceptEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(g, f, rs[1]);
- assertTrue(fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
-
- // unspecified behavior - both source completions available
- try {
- assertEquals(null, h0.join());
- rs[0].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h0, ex);
- rs[0].assertNotInvoked();
- }
- try {
- assertEquals(null, h1.join());
- rs[1].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h1, ex);
- rs[1].assertNotInvoked();
- }
- try {
- assertEquals(null, h2.join());
- rs[2].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h2, ex);
- rs[2].assertNotInvoked();
- }
- try {
- assertEquals(null, h3.join());
- rs[3].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h3, ex);
- rs[3].assertNotInvoked();
- }
-
- checkCompletedNormally(f, v1);
- checkCompletedExceptionally(g, ex);
- }}
-
- /**
- * acceptEither result completes exceptionally if either source cancelled
- */
- public void testAcceptEither_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final NoopConsumer[] rs = new NoopConsumer[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m);
-
- final CompletableFuture<Void> h0 = m.acceptEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.cancel(mayInterruptIfRunning);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
-
- g.complete(v1);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.acceptEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.acceptEither(g, f, rs[5]);
- try {
- assertNull(h4.join());
- rs[4].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h4);
- rs[4].assertNotInvoked();
- }
- try {
- assertNull(h5.join());
- rs[5].assertValue(v1);
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h5);
- rs[5].assertNotInvoked();
- }
-
- checkCancelled(f);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- /**
- * acceptEither result completes exceptionally if action does
- */
- public void testAcceptEither_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingConsumer[] rs = new FailingConsumer[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingConsumer(m);
-
- final CompletableFuture<Void> h0 = m.acceptEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.acceptEither(g, f, rs[1]);
- f.complete(v1);
- final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertValue(v1);
-
- g.complete(v2);
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.acceptEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.acceptEither(g, f, rs[5]);
-
- checkCompletedWithWrappedCFException(h4);
- assertTrue(Objects.equals(v1, rs[4].value) ||
- Objects.equals(v2, rs[4].value));
- checkCompletedWithWrappedCFException(h5);
- assertTrue(Objects.equals(v1, rs[5].value) ||
- Objects.equals(v2, rs[5].value));
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- }}
-
- /**
- * runAfterEither result completes normally after normal completion
- * of either source
- */
- public void testRunAfterEither_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.runAfterEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.complete(v1);
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- rs[0].assertInvoked();
- rs[1].assertInvoked();
- final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- rs[2].assertInvoked();
- rs[3].assertInvoked();
-
- g.complete(v2);
-
- final CompletableFuture<Void> h4 = m.runAfterEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(g, f, rs[5]);
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- checkCompletedNormally(h0, null);
- checkCompletedNormally(h1, null);
- checkCompletedNormally(h2, null);
- checkCompletedNormally(h3, null);
- checkCompletedNormally(h4, null);
- checkCompletedNormally(h5, null);
- for (int i = 0; i < 6; i++) rs[i].assertInvoked();
- }}
-
- /**
- * runAfterEither result completes exceptionally after exceptional
- * completion of either source
- */
- public void testRunAfterEither_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.runAfterEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- assertTrue(f.completeExceptionally(ex));
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
-
- assertTrue(g.complete(v1));
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.runAfterEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(g, f, rs[5]);
- try {
- assertNull(h4.join());
- rs[4].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h4, ex);
- rs[4].assertNotInvoked();
- }
- try {
- assertNull(h5.join());
- rs[5].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h5, ex);
- rs[5].assertNotInvoked();
- }
-
- checkCompletedExceptionally(f, ex);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedException(h0, ex);
- checkCompletedWithWrappedException(h1, ex);
- checkCompletedWithWrappedException(h2, ex);
- checkCompletedWithWrappedException(h3, ex);
- checkCompletedWithWrappedException(h4, ex);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- public void testRunAfterEither_exceptionalCompletion2() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean fFirst : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CFException ex = new CFException();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.runAfterEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterEither(g, f, rs[1]);
- assertTrue( fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex));
- final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
-
- // unspecified behavior - both source completions available
- try {
- assertEquals(null, h0.join());
- rs[0].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h0, ex);
- rs[0].assertNotInvoked();
- }
- try {
- assertEquals(null, h1.join());
- rs[1].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h1, ex);
- rs[1].assertNotInvoked();
- }
- try {
- assertEquals(null, h2.join());
- rs[2].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h2, ex);
- rs[2].assertNotInvoked();
- }
- try {
- assertEquals(null, h3.join());
- rs[3].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedException(h3, ex);
- rs[3].assertNotInvoked();
- }
-
- checkCompletedNormally(f, v1);
- checkCompletedExceptionally(g, ex);
- }}
-
- /**
- * runAfterEither result completes exceptionally if either source cancelled
- */
- public void testRunAfterEither_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final Noop[] rs = new Noop[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m);
-
- final CompletableFuture<Void> h0 = m.runAfterEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterEither(g, f, rs[1]);
- checkIncomplete(h0);
- checkIncomplete(h1);
- rs[0].assertNotInvoked();
- rs[1].assertNotInvoked();
- f.cancel(mayInterruptIfRunning);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
-
- assertTrue(g.complete(v1));
-
- // unspecified behavior - both source completions available
- final CompletableFuture<Void> h4 = m.runAfterEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(g, f, rs[5]);
- try {
- assertNull(h4.join());
- rs[4].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h4);
- rs[4].assertNotInvoked();
- }
- try {
- assertNull(h5.join());
- rs[5].assertInvoked();
- } catch (CompletionException ok) {
- checkCompletedWithWrappedCancellationException(h5);
- rs[5].assertNotInvoked();
- }
-
- checkCancelled(f);
- checkCompletedNormally(g, v1);
- checkCompletedWithWrappedCancellationException(h0);
- checkCompletedWithWrappedCancellationException(h1);
- checkCompletedWithWrappedCancellationException(h2);
- checkCompletedWithWrappedCancellationException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertNotInvoked();
- }}
-
- /**
- * runAfterEither result completes exceptionally if action does
- */
- public void testRunAfterEither_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (Integer v1 : new Integer[] { 1, null })
- for (Integer v2 : new Integer[] { 2, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final FailingRunnable[] rs = new FailingRunnable[6];
- for (int i = 0; i < rs.length; i++) rs[i] = new FailingRunnable(m);
-
- final CompletableFuture<Void> h0 = m.runAfterEither(f, g, rs[0]);
- final CompletableFuture<Void> h1 = m.runAfterEither(g, f, rs[1]);
- assertTrue(f.complete(v1));
- final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
- final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
- checkCompletedWithWrappedCFException(h0);
- checkCompletedWithWrappedCFException(h1);
- checkCompletedWithWrappedCFException(h2);
- checkCompletedWithWrappedCFException(h3);
- for (int i = 0; i < 4; i++) rs[i].assertInvoked();
- assertTrue(g.complete(v2));
- final CompletableFuture<Void> h4 = m.runAfterEither(f, g, rs[4]);
- final CompletableFuture<Void> h5 = m.runAfterEither(g, f, rs[5]);
- checkCompletedWithWrappedCFException(h4);
- checkCompletedWithWrappedCFException(h5);
-
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v2);
- for (int i = 0; i < 6; i++) rs[i].assertInvoked();
- }}
-
- /**
- * thenCompose result completes normally after normal completion of source
- */
- public void testThenCompose_normalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFutureInc r = new CompletableFutureInc(m);
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.thenCompose(f, r);
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedNormally(g, inc(v1));
- checkCompletedNormally(f, v1);
- r.assertValue(v1);
- }}
-
- /**
- * thenCompose result completes exceptionally after exceptional
- * completion of source
- */
- public void testThenCompose_exceptionalCompletion() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- {
- final CFException ex = new CFException();
- final CompletableFutureInc r = new CompletableFutureInc(m);
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- if (!createIncomplete) f.completeExceptionally(ex);
- final CompletableFuture<Integer> g = m.thenCompose(f, r);
- if (createIncomplete) f.completeExceptionally(ex);
-
- checkCompletedWithWrappedException(g, ex);
- checkCompletedExceptionally(f, ex);
- r.assertNotInvoked();
- }}
-
- /**
- * thenCompose result completes exceptionally if action does
- */
- public void testThenCompose_actionFailed() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final FailingCompletableFutureFunction r
- = new FailingCompletableFutureFunction(m);
- if (!createIncomplete) assertTrue(f.complete(v1));
- final CompletableFuture<Integer> g = m.thenCompose(f, r);
- if (createIncomplete) assertTrue(f.complete(v1));
-
- checkCompletedWithWrappedCFException(g);
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * thenCompose result completes exceptionally if source cancelled
- */
- public void testThenCompose_sourceCancelled() {
- for (ExecutionMode m : ExecutionMode.values())
- for (boolean createIncomplete : new boolean[] { true, false })
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- {
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFutureInc r = new CompletableFutureInc(m);
- if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
- final CompletableFuture<Integer> g = m.thenCompose(f, r);
- if (createIncomplete) {
- checkIncomplete(g);
- assertTrue(f.cancel(mayInterruptIfRunning));
- }
-
- checkCompletedWithWrappedCancellationException(g);
- checkCancelled(f);
- }}
-
- /**
- * thenCompose result completes exceptionally if the result of the action does
- */
- public void testThenCompose_actionReturnsFailingFuture() {
- for (ExecutionMode m : ExecutionMode.values())
- for (int order = 0; order < 6; order++)
- for (Integer v1 : new Integer[] { 1, null })
- {
- final CFException ex = new CFException();
- final CompletableFuture<Integer> f = new CompletableFuture<>();
- final CompletableFuture<Integer> g = new CompletableFuture<>();
- final CompletableFuture<Integer> h;
- // Test all permutations of orders
- switch (order) {
- case 0:
- assertTrue(f.complete(v1));
- assertTrue(g.completeExceptionally(ex));
- h = m.thenCompose(f, (x -> g));
- break;
- case 1:
- assertTrue(f.complete(v1));
- h = m.thenCompose(f, (x -> g));
- assertTrue(g.completeExceptionally(ex));
- break;
- case 2:
- assertTrue(g.completeExceptionally(ex));
- assertTrue(f.complete(v1));
- h = m.thenCompose(f, (x -> g));
- break;
- case 3:
- assertTrue(g.completeExceptionally(ex));
- h = m.thenCompose(f, (x -> g));
- assertTrue(f.complete(v1));
- break;
- case 4:
- h = m.thenCompose(f, (x -> g));
- assertTrue(f.complete(v1));
- assertTrue(g.completeExceptionally(ex));
- break;
- case 5:
- h = m.thenCompose(f, (x -> g));
- assertTrue(f.complete(v1));
- assertTrue(g.completeExceptionally(ex));
- break;
- default: throw new AssertionError();
- }
-
- checkCompletedExceptionally(g, ex);
- checkCompletedWithWrappedException(h, ex);
- checkCompletedNormally(f, v1);
- }}
-
- // other static methods
-
- /**
- * allOf(no component futures) returns a future completed normally
- * with the value null
- */
- public void testAllOf_empty() throws Exception {
- CompletableFuture<Void> f = CompletableFuture.allOf();
- checkCompletedNormally(f, null);
- }
-
- /**
- * allOf returns a future completed normally with the value null
- * when all components complete normally
- */
- public void testAllOf_normal() throws Exception {
- for (int k = 1; k < 10; k++) {
- CompletableFuture<Integer>[] fs
- = (CompletableFuture<Integer>[]) new CompletableFuture[k];
- for (int i = 0; i < k; i++)
- fs[i] = new CompletableFuture<>();
- CompletableFuture<Void> f = CompletableFuture.allOf(fs);
- for (int i = 0; i < k; i++) {
- checkIncomplete(f);
- checkIncomplete(CompletableFuture.allOf(fs));
- fs[i].complete(one);
- }
- checkCompletedNormally(f, null);
- checkCompletedNormally(CompletableFuture.allOf(fs), null);
- }
- }
-
- public void testAllOf_backwards() throws Exception {
- for (int k = 1; k < 10; k++) {
- CompletableFuture<Integer>[] fs
- = (CompletableFuture<Integer>[]) new CompletableFuture[k];
- for (int i = 0; i < k; i++)
- fs[i] = new CompletableFuture<>();
- CompletableFuture<Void> f = CompletableFuture.allOf(fs);
- for (int i = k - 1; i >= 0; i--) {
- checkIncomplete(f);
- checkIncomplete(CompletableFuture.allOf(fs));
- fs[i].complete(one);
- }
- checkCompletedNormally(f, null);
- checkCompletedNormally(CompletableFuture.allOf(fs), null);
- }
- }
-
- public void testAllOf_exceptional() throws Exception {
- for (int k = 1; k < 10; k++) {
- CompletableFuture<Integer>[] fs
- = (CompletableFuture<Integer>[]) new CompletableFuture[k];
- CFException ex = new CFException();
- for (int i = 0; i < k; i++)
- fs[i] = new CompletableFuture<>();
- CompletableFuture<Void> f = CompletableFuture.allOf(fs);
- for (int i = 0; i < k; i++) {
- checkIncomplete(f);
- checkIncomplete(CompletableFuture.allOf(fs));
- if (i != k / 2) {
- fs[i].complete(i);
- checkCompletedNormally(fs[i], i);
- } else {
- fs[i].completeExceptionally(ex);
- checkCompletedExceptionally(fs[i], ex);
- }
- }
- checkCompletedWithWrappedException(f, ex);
- checkCompletedWithWrappedException(CompletableFuture.allOf(fs), ex);
- }
- }
-
- /**
- * anyOf(no component futures) returns an incomplete future
- */
- public void testAnyOf_empty() throws Exception {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Object> f = CompletableFuture.anyOf();
- checkIncomplete(f);
-
- f.complete(v1);
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * anyOf returns a future completed normally with a value when
- * a component future does
- */
- public void testAnyOf_normal() throws Exception {
- for (int k = 0; k < 10; k++) {
- CompletableFuture[] fs = new CompletableFuture[k];
- for (int i = 0; i < k; i++)
- fs[i] = new CompletableFuture<>();
- CompletableFuture<Object> f = CompletableFuture.anyOf(fs);
- checkIncomplete(f);
- for (int i = 0; i < k; i++) {
- fs[i].complete(i);
- checkCompletedNormally(f, 0);
- int x = (int) CompletableFuture.anyOf(fs).join();
- assertTrue(0 <= x && x <= i);
- }
- }
- }
- public void testAnyOf_normal_backwards() throws Exception {
- for (int k = 0; k < 10; k++) {
- CompletableFuture[] fs = new CompletableFuture[k];
- for (int i = 0; i < k; i++)
- fs[i] = new CompletableFuture<>();
- CompletableFuture<Object> f = CompletableFuture.anyOf(fs);
- checkIncomplete(f);
- for (int i = k - 1; i >= 0; i--) {
- fs[i].complete(i);
- checkCompletedNormally(f, k - 1);
- int x = (int) CompletableFuture.anyOf(fs).join();
- assertTrue(i <= x && x <= k - 1);
- }
- }
- }
-
- /**
- * anyOf result completes exceptionally when any component does.
- */
- public void testAnyOf_exceptional() throws Exception {
- for (int k = 0; k < 10; k++) {
- CompletableFuture[] fs = new CompletableFuture[k];
- CFException[] exs = new CFException[k];
- for (int i = 0; i < k; i++) {
- fs[i] = new CompletableFuture<>();
- exs[i] = new CFException();
- }
- CompletableFuture<Object> f = CompletableFuture.anyOf(fs);
- checkIncomplete(f);
- for (int i = 0; i < k; i++) {
- fs[i].completeExceptionally(exs[i]);
- checkCompletedWithWrappedException(f, exs[0]);
- checkCompletedWithWrappedCFException(CompletableFuture.anyOf(fs));
- }
- }
- }
-
- public void testAnyOf_exceptional_backwards() throws Exception {
- for (int k = 0; k < 10; k++) {
- CompletableFuture[] fs = new CompletableFuture[k];
- CFException[] exs = new CFException[k];
- for (int i = 0; i < k; i++) {
- fs[i] = new CompletableFuture<>();
- exs[i] = new CFException();
- }
- CompletableFuture<Object> f = CompletableFuture.anyOf(fs);
- checkIncomplete(f);
- for (int i = k - 1; i >= 0; i--) {
- fs[i].completeExceptionally(exs[i]);
- checkCompletedWithWrappedException(f, exs[k - 1]);
- checkCompletedWithWrappedCFException(CompletableFuture.anyOf(fs));
- }
- }
- }
-
- /**
- * Completion methods throw NullPointerException with null arguments
- */
- public void testNPE() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = new CompletableFuture<>();
- CompletableFuture<Integer> nullFuture = (CompletableFuture<Integer>)null;
- ThreadExecutor exec = new ThreadExecutor();
-
- Runnable[] throwingActions = {
- () -> CompletableFuture.supplyAsync(null),
- () -> CompletableFuture.supplyAsync(null, exec),
- () -> CompletableFuture.supplyAsync(new IntegerSupplier(ExecutionMode.SYNC, 42), null),
-
- () -> CompletableFuture.runAsync(null),
- () -> CompletableFuture.runAsync(null, exec),
- () -> CompletableFuture.runAsync(() -> {}, null),
-
- () -> f.completeExceptionally(null),
-
- () -> f.thenApply(null),
- () -> f.thenApplyAsync(null),
- () -> f.thenApplyAsync((x) -> x, null),
- () -> f.thenApplyAsync(null, exec),
-
- () -> f.thenAccept(null),
- () -> f.thenAcceptAsync(null),
- () -> f.thenAcceptAsync((x) -> {} , null),
- () -> f.thenAcceptAsync(null, exec),
-
- () -> f.thenRun(null),
- () -> f.thenRunAsync(null),
- () -> f.thenRunAsync(() -> {} , null),
- () -> f.thenRunAsync(null, exec),
-
- () -> f.thenCombine(g, null),
- () -> f.thenCombineAsync(g, null),
- () -> f.thenCombineAsync(g, null, exec),
- () -> f.thenCombine(nullFuture, (x, y) -> x),
- () -> f.thenCombineAsync(nullFuture, (x, y) -> x),
- () -> f.thenCombineAsync(nullFuture, (x, y) -> x, exec),
- () -> f.thenCombineAsync(g, (x, y) -> x, null),
-
- () -> f.thenAcceptBoth(g, null),
- () -> f.thenAcceptBothAsync(g, null),
- () -> f.thenAcceptBothAsync(g, null, exec),
- () -> f.thenAcceptBoth(nullFuture, (x, y) -> {}),
- () -> f.thenAcceptBothAsync(nullFuture, (x, y) -> {}),
- () -> f.thenAcceptBothAsync(nullFuture, (x, y) -> {}, exec),
- () -> f.thenAcceptBothAsync(g, (x, y) -> {}, null),
-
- () -> f.runAfterBoth(g, null),
- () -> f.runAfterBothAsync(g, null),
- () -> f.runAfterBothAsync(g, null, exec),
- () -> f.runAfterBoth(nullFuture, () -> {}),
- () -> f.runAfterBothAsync(nullFuture, () -> {}),
- () -> f.runAfterBothAsync(nullFuture, () -> {}, exec),
- () -> f.runAfterBothAsync(g, () -> {}, null),
-
- () -> f.applyToEither(g, null),
- () -> f.applyToEitherAsync(g, null),
- () -> f.applyToEitherAsync(g, null, exec),
- () -> f.applyToEither(nullFuture, (x) -> x),
- () -> f.applyToEitherAsync(nullFuture, (x) -> x),
- () -> f.applyToEitherAsync(nullFuture, (x) -> x, exec),
- () -> f.applyToEitherAsync(g, (x) -> x, null),
-
- () -> f.acceptEither(g, null),
- () -> f.acceptEitherAsync(g, null),
- () -> f.acceptEitherAsync(g, null, exec),
- () -> f.acceptEither(nullFuture, (x) -> {}),
- () -> f.acceptEitherAsync(nullFuture, (x) -> {}),
- () -> f.acceptEitherAsync(nullFuture, (x) -> {}, exec),
- () -> f.acceptEitherAsync(g, (x) -> {}, null),
-
- () -> f.runAfterEither(g, null),
- () -> f.runAfterEitherAsync(g, null),
- () -> f.runAfterEitherAsync(g, null, exec),
- () -> f.runAfterEither(nullFuture, () -> {}),
- () -> f.runAfterEitherAsync(nullFuture, () -> {}),
- () -> f.runAfterEitherAsync(nullFuture, () -> {}, exec),
- () -> f.runAfterEitherAsync(g, () -> {}, null),
-
- () -> f.thenCompose(null),
- () -> f.thenComposeAsync(null),
- () -> f.thenComposeAsync(new CompletableFutureInc(ExecutionMode.EXECUTOR), null),
- () -> f.thenComposeAsync(null, exec),
-
- () -> f.exceptionally(null),
-
- () -> f.handle(null),
-
- () -> CompletableFuture.allOf((CompletableFuture<?>)null),
- () -> CompletableFuture.allOf((CompletableFuture<?>[])null),
- () -> CompletableFuture.allOf(f, null),
- () -> CompletableFuture.allOf(null, f),
-
- () -> CompletableFuture.anyOf((CompletableFuture<?>)null),
- () -> CompletableFuture.anyOf((CompletableFuture<?>[])null),
- () -> CompletableFuture.anyOf(f, null),
- () -> CompletableFuture.anyOf(null, f),
-
- () -> f.obtrudeException(null),
-
- () -> CompletableFuture.delayedExecutor(1L, SECONDS, null),
- () -> CompletableFuture.delayedExecutor(1L, null, new ThreadExecutor()),
- () -> CompletableFuture.delayedExecutor(1L, null),
-
- () -> f.orTimeout(1L, null),
- () -> f.completeOnTimeout(42, 1L, null),
-
- () -> CompletableFuture.failedFuture(null),
- () -> CompletableFuture.failedStage(null),
- };
-
- assertThrows(NullPointerException.class, throwingActions);
- assertEquals(0, exec.count.get());
- }
-
- /**
- * toCompletableFuture returns this CompletableFuture.
- */
- public void testToCompletableFuture() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- assertSame(f, f.toCompletableFuture());
- }
-
- // jdk9
-
- /**
- * newIncompleteFuture returns an incomplete CompletableFuture
- */
- public void testNewIncompleteFuture() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = f.newIncompleteFuture();
- checkIncomplete(f);
- checkIncomplete(g);
- f.complete(v1);
- checkCompletedNormally(f, v1);
- checkIncomplete(g);
- g.complete(v1);
- checkCompletedNormally(g, v1);
- assertSame(g.getClass(), CompletableFuture.class);
- }}
-
- /**
- * completedStage returns a completed CompletionStage
- */
- public void testCompletedStage() {
- AtomicInteger x = new AtomicInteger(0);
- AtomicReference<Throwable> r = new AtomicReference<Throwable>();
- CompletionStage<Integer> f = CompletableFuture.completedStage(1);
- f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
- assertEquals(x.get(), 1);
- assertNull(r.get());
- }
-
- /**
- * defaultExecutor by default returns the commonPool if
- * it supports more than one thread.
- */
- public void testDefaultExecutor() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- Executor e = f.defaultExecutor();
- Executor c = ForkJoinPool.commonPool();
- if (ForkJoinPool.getCommonPoolParallelism() > 1)
- assertSame(e, c);
- else
- assertNotSame(e, c);
- }
-
- /**
- * failedFuture returns a CompletableFuture completed
- * exceptionally with the given Exception
- */
- public void testFailedFuture() {
- CFException ex = new CFException();
- CompletableFuture<Integer> f = CompletableFuture.failedFuture(ex);
- checkCompletedExceptionally(f, ex);
- }
-
- /**
- * failedFuture(null) throws NPE
- */
- public void testFailedFuture_null() {
- try {
- CompletableFuture<Integer> f = CompletableFuture.failedFuture(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
-
- /**
- * copy returns a CompletableFuture that is completed normally,
- * with the same value, when source is.
- */
- public void testCopy() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = f.copy();
- checkIncomplete(f);
- checkIncomplete(g);
- f.complete(1);
- checkCompletedNormally(f, 1);
- checkCompletedNormally(g, 1);
- }
-
- /**
- * copy returns a CompletableFuture that is completed exceptionally
- * when source is.
- */
- public void testCopy2() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = f.copy();
- checkIncomplete(f);
- checkIncomplete(g);
- CFException ex = new CFException();
- f.completeExceptionally(ex);
- checkCompletedExceptionally(f, ex);
- checkCompletedWithWrappedException(g, ex);
- }
-
- /**
- * minimalCompletionStage returns a CompletableFuture that is
- * completed normally, with the same value, when source is.
- */
- public void testMinimalCompletionStage() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletionStage<Integer> g = f.minimalCompletionStage();
- AtomicInteger x = new AtomicInteger(0);
- AtomicReference<Throwable> r = new AtomicReference<Throwable>();
- checkIncomplete(f);
- g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
- f.complete(1);
- checkCompletedNormally(f, 1);
- assertEquals(x.get(), 1);
- assertNull(r.get());
- }
-
- /**
- * minimalCompletionStage returns a CompletableFuture that is
- * completed exceptionally when source is.
- */
- public void testMinimalCompletionStage2() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletionStage<Integer> g = f.minimalCompletionStage();
- AtomicInteger x = new AtomicInteger(0);
- AtomicReference<Throwable> r = new AtomicReference<Throwable>();
- g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
- checkIncomplete(f);
- CFException ex = new CFException();
- f.completeExceptionally(ex);
- checkCompletedExceptionally(f, ex);
- assertEquals(x.get(), 0);
- assertEquals(r.get().getCause(), ex);
- }
-
- /**
- * failedStage returns a CompletionStage completed
- * exceptionally with the given Exception
- */
- public void testFailedStage() {
- CFException ex = new CFException();
- CompletionStage<Integer> f = CompletableFuture.failedStage(ex);
- AtomicInteger x = new AtomicInteger(0);
- AtomicReference<Throwable> r = new AtomicReference<Throwable>();
- f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
- assertEquals(x.get(), 0);
- assertEquals(r.get(), ex);
- }
-
- /**
- * completeAsync completes with value of given supplier
- */
- public void testCompleteAsync() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- f.completeAsync(() -> v1);
- f.join();
- checkCompletedNormally(f, v1);
- }}
-
- /**
- * completeAsync completes exceptionally if given supplier throws
- */
- public void testCompleteAsync2() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CFException ex = new CFException();
- f.completeAsync(() -> {if (true) throw ex; return 1;});
- try {
- f.join();
- shouldThrow();
- } catch (CompletionException success) {}
- checkCompletedWithWrappedException(f, ex);
- }
-
- /**
- * completeAsync with given executor completes with value of given supplier
- */
- public void testCompleteAsync3() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- ThreadExecutor executor = new ThreadExecutor();
- f.completeAsync(() -> v1, executor);
- assertSame(v1, f.join());
- checkCompletedNormally(f, v1);
- assertEquals(1, executor.count.get());
- }}
-
- /**
- * completeAsync with given executor completes exceptionally if
- * given supplier throws
- */
- public void testCompleteAsync4() {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CFException ex = new CFException();
- ThreadExecutor executor = new ThreadExecutor();
- f.completeAsync(() -> {if (true) throw ex; return 1;}, executor);
- try {
- f.join();
- shouldThrow();
- } catch (CompletionException success) {}
- checkCompletedWithWrappedException(f, ex);
- assertEquals(1, executor.count.get());
- }
-
- /**
- * orTimeout completes with TimeoutException if not complete
- */
- public void testOrTimeout_timesOut() {
- long timeoutMillis = timeoutMillis();
- CompletableFuture<Integer> f = new CompletableFuture<>();
- long startTime = System.nanoTime();
- f.orTimeout(timeoutMillis, MILLISECONDS);
- checkCompletedWithTimeoutException(f);
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- }
-
- /**
- * orTimeout completes normally if completed before timeout
- */
- public void testOrTimeout_completed() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = new CompletableFuture<>();
- long startTime = System.nanoTime();
- f.complete(v1);
- f.orTimeout(LONG_DELAY_MS, MILLISECONDS);
- g.orTimeout(LONG_DELAY_MS, MILLISECONDS);
- g.complete(v1);
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v1);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
- }}
-
- /**
- * completeOnTimeout completes with given value if not complete
- */
- public void testCompleteOnTimeout_timesOut() {
- testInParallel(() -> testCompleteOnTimeout_timesOut(42),
- () -> testCompleteOnTimeout_timesOut(null));
- }
-
- public void testCompleteOnTimeout_timesOut(Integer v) {
- long timeoutMillis = timeoutMillis();
- CompletableFuture<Integer> f = new CompletableFuture<>();
- long startTime = System.nanoTime();
- f.completeOnTimeout(v, timeoutMillis, MILLISECONDS);
- assertSame(v, f.join());
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- f.complete(99); // should have no effect
- checkCompletedNormally(f, v);
- }
-
- /**
- * completeOnTimeout has no effect if completed within timeout
- */
- public void testCompleteOnTimeout_completed() {
- for (Integer v1 : new Integer[] { 1, null })
- {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> g = new CompletableFuture<>();
- long startTime = System.nanoTime();
- f.complete(v1);
- f.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS);
- g.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS);
- g.complete(v1);
- checkCompletedNormally(f, v1);
- checkCompletedNormally(g, v1);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
- }}
-
- /**
- * delayedExecutor returns an executor that delays submission
- */
- public void testDelayedExecutor() {
- testInParallel(() -> testDelayedExecutor(null, null),
- () -> testDelayedExecutor(null, 1),
- () -> testDelayedExecutor(new ThreadExecutor(), 1),
- () -> testDelayedExecutor(new ThreadExecutor(), 1));
- }
-
- public void testDelayedExecutor(Executor executor, Integer v) throws Exception {
- long timeoutMillis = timeoutMillis();
- // Use an "unreasonably long" long timeout to catch lingering threads
- long longTimeoutMillis = 1000 * 60 * 60 * 24;
- final Executor delayer, longDelayer;
- if (executor == null) {
- delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS);
- longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS);
- } else {
- delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS, executor);
- longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS, executor);
- }
- long startTime = System.nanoTime();
- CompletableFuture<Integer> f =
- CompletableFuture.supplyAsync(() -> v, delayer);
- CompletableFuture<Integer> g =
- CompletableFuture.supplyAsync(() -> v, longDelayer);
-
- assertNull(g.getNow(null));
-
- assertSame(v, f.get(LONG_DELAY_MS, MILLISECONDS));
- long millisElapsed = millisElapsedSince(startTime);
- assertTrue(millisElapsed >= timeoutMillis);
- assertTrue(millisElapsed < LONG_DELAY_MS / 2);
-
- checkCompletedNormally(f, v);
-
- checkIncomplete(g);
- assertTrue(g.cancel(true));
- }
-
- //--- tests of implementation details; not part of official tck ---
-
- Object resultOf(CompletableFuture<?> f) {
- try {
- java.lang.reflect.Field resultField
- = CompletableFuture.class.getDeclaredField("result");
- resultField.setAccessible(true);
- return resultField.get(f);
- } catch (Throwable t) { throw new AssertionError(t); }
- }
-
- public void testExceptionPropagationReusesResultObject() {
- if (!testImplementationDetails) return;
- for (ExecutionMode m : ExecutionMode.values())
- {
- final CFException ex = new CFException();
- final CompletableFuture<Integer> v42 = CompletableFuture.completedFuture(42);
- final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
-
- List<Function<CompletableFuture<Integer>, CompletableFuture<?>>> funs
- = new ArrayList<>();
-
- funs.add((y) -> m.thenRun(y, new Noop(m)));
- funs.add((y) -> m.thenAccept(y, new NoopConsumer(m)));
- funs.add((y) -> m.thenApply(y, new IncFunction(m)));
-
- funs.add((y) -> m.runAfterEither(y, incomplete, new Noop(m)));
- funs.add((y) -> m.acceptEither(y, incomplete, new NoopConsumer(m)));
- funs.add((y) -> m.applyToEither(y, incomplete, new IncFunction(m)));
-
- funs.add((y) -> m.runAfterBoth(y, v42, new Noop(m)));
- funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
- funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m)));
-
- funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
-
- funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m)));
-
- funs.add((y) -> CompletableFuture.allOf(new CompletableFuture<?>[] {y, v42}));
- funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture<?>[] {y, incomplete}));
-
- for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
- fun : funs) {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- f.completeExceptionally(ex);
- CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
- checkCompletedWithWrappedException(src, ex);
- CompletableFuture<?> dep = fun.apply(src);
- checkCompletedWithWrappedException(dep, ex);
- assertSame(resultOf(src), resultOf(dep));
- }
-
- for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
- fun : funs) {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
- CompletableFuture<?> dep = fun.apply(src);
- f.completeExceptionally(ex);
- checkCompletedWithWrappedException(src, ex);
- checkCompletedWithWrappedException(dep, ex);
- assertSame(resultOf(src), resultOf(dep));
- }
-
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
- fun : funs) {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- f.cancel(mayInterruptIfRunning);
- checkCancelled(f);
- CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
- checkCompletedWithWrappedCancellationException(src);
- CompletableFuture<?> dep = fun.apply(src);
- checkCompletedWithWrappedCancellationException(dep);
- assertSame(resultOf(src), resultOf(dep));
- }
-
- for (boolean mayInterruptIfRunning : new boolean[] { true, false })
- for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
- fun : funs) {
- CompletableFuture<Integer> f = new CompletableFuture<>();
- CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
- CompletableFuture<?> dep = fun.apply(src);
- f.cancel(mayInterruptIfRunning);
- checkCancelled(f);
- checkCompletedWithWrappedCancellationException(src);
- checkCompletedWithWrappedCancellationException(dep);
- assertSame(resultOf(src), resultOf(dep));
- }
- }}
-
- /**
- * Minimal completion stages throw UOE for all non-CompletionStage methods
- */
- // TODO(streams):
- // public void testMinimalCompletionStage_minimality() {
- // if (!testImplementationDetails) return;
- // Function<Method, String> toSignature =
- // (method) -> method.getName() + Arrays.toString(method.getParameterTypes());
- // Predicate<Method> isNotStatic =
- // (method) -> (method.getModifiers() & Modifier.STATIC) == 0;
- // List<Method> minimalMethods =
- // Stream.of(Object.class, CompletionStage.class)
- // .flatMap((klazz) -> Stream.of(klazz.getMethods()))
- // .filter(isNotStatic)
- // .collect(Collectors.toList());
- // // Methods from CompletableFuture permitted NOT to throw UOE
- // String[] signatureWhitelist = {
- // "newIncompleteFuture[]",
- // "defaultExecutor[]",
- // "minimalCompletionStage[]",
- // "copy[]",
- // };
- // Set<String> permittedMethodSignatures =
- // Stream.concat(minimalMethods.stream().map(toSignature),
- // Stream.of(signatureWhitelist))
- // .collect(Collectors.toSet());
- // List<Method> allMethods = Stream.of(CompletableFuture.class.getMethods())
- // .filter(isNotStatic)
- // .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method)))
- // .collect(Collectors.toList());
-
- // CompletionStage<Integer> minimalStage =
- // new CompletableFuture<Integer>().minimalCompletionStage();
-
- // List<Method> bugs = new ArrayList<>();
- // for (Method method : allMethods) {
- // Class<?>[] parameterTypes = method.getParameterTypes();
- // Object[] args = new Object[parameterTypes.length];
- // // Manufacture boxed primitives for primitive params
- // for (int i = 0; i < args.length; i++) {
- // Class<?> type = parameterTypes[i];
- // if (parameterTypes[i] == boolean.class)
- // args[i] = false;
- // else if (parameterTypes[i] == int.class)
- // args[i] = 0;
- // else if (parameterTypes[i] == long.class)
- // args[i] = 0L;
- // }
- // try {
- // method.invoke(minimalStage, args);
- // bugs.add(method);
- // }
- // catch (java.lang.reflect.InvocationTargetException expected) {
- // if (! (expected.getCause() instanceof UnsupportedOperationException)) {
- // bugs.add(method);
- // // expected.getCause().printStackTrace();
- // }
- // }
- // catch (ReflectiveOperationException bad) { throw new Error(bad); }
- // }
- // if (!bugs.isEmpty())
- // throw new Error("Methods did not throw UOE: " + bugs.toString());
- // }
-
- static class Monad {
- static class ZeroException extends RuntimeException {
- public ZeroException() { super("monadic zero"); }
- }
- // "return", "unit"
- static <T> CompletableFuture<T> unit(T value) {
- return completedFuture(value);
- }
- // monadic zero ?
- static <T> CompletableFuture<T> zero() {
- return failedFuture(new ZeroException());
- }
- // >=>
- static <T,U,V> Function<T, CompletableFuture<V>> compose
- (Function<T, CompletableFuture<U>> f,
- Function<U, CompletableFuture<V>> g) {
- return (x) -> f.apply(x).thenCompose(g);
- }
-
- static void assertZero(CompletableFuture<?> f) {
- try {
- f.getNow(null);
- throw new AssertionFailedError("should throw");
- } catch (CompletionException success) {
- assertTrue(success.getCause() instanceof ZeroException);
- }
- }
-
- static <T> void assertFutureEquals(CompletableFuture<T> f,
- CompletableFuture<T> g) {
- T fval = null, gval = null;
- Throwable fex = null, gex = null;
-
- try { fval = f.get(); }
- catch (ExecutionException ex) { fex = ex.getCause(); }
- catch (Throwable ex) { fex = ex; }
-
- try { gval = g.get(); }
- catch (ExecutionException ex) { gex = ex.getCause(); }
- catch (Throwable ex) { gex = ex; }
-
- if (fex != null || gex != null)
- assertSame(fex.getClass(), gex.getClass());
- else
- assertEquals(fval, gval);
- }
-
- static class PlusFuture<T> extends CompletableFuture<T> {
- AtomicReference<Throwable> firstFailure = new AtomicReference<>(null);
- }
-
- /** Implements "monadic plus". */
- static <T> CompletableFuture<T> plus(CompletableFuture<? extends T> f,
- CompletableFuture<? extends T> g) {
- PlusFuture<T> plus = new PlusFuture<T>();
- BiConsumer<T, Throwable> action = (T result, Throwable ex) -> {
- try {
- if (ex == null) {
- if (plus.complete(result))
- if (plus.firstFailure.get() != null)
- plus.firstFailure.set(null);
- }
- else if (plus.firstFailure.compareAndSet(null, ex)) {
- if (plus.isDone())
- plus.firstFailure.set(null);
- }
- else {
- // first failure has precedence
- Throwable first = plus.firstFailure.getAndSet(null);
-
- // may fail with "Self-suppression not permitted"
- try { first.addSuppressed(ex); }
- catch (Exception ignored) {}
-
- plus.completeExceptionally(first);
- }
- } catch (Throwable unexpected) {
- plus.completeExceptionally(unexpected);
- }
- };
- f.whenComplete(action);
- g.whenComplete(action);
- return plus;
- }
- }
-
- /**
- * CompletableFuture is an additive monad - sort of.
- * https://en.wikipedia.org/wiki/Monad_(functional_programming)#Additive_monads
- */
- public void testAdditiveMonad() throws Throwable {
- Function<Long, CompletableFuture<Long>> unit = Monad::unit;
- CompletableFuture<Long> zero = Monad.zero();
-
- // Some mutually non-commutative functions
- Function<Long, CompletableFuture<Long>> triple
- = (x) -> Monad.unit(3 * x);
- Function<Long, CompletableFuture<Long>> inc
- = (x) -> Monad.unit(x + 1);
-
- // unit is a right identity: m >>= unit === m
- Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit),
- inc.apply(5L));
- // unit is a left identity: (unit x) >>= f === f x
- Monad.assertFutureEquals(unit.apply(5L).thenCompose(inc),
- inc.apply(5L));
-
- // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) )
- Monad.assertFutureEquals(
- unit.apply(5L).thenCompose(inc).thenCompose(triple),
- unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple)));
-
- // The case for CompletableFuture as an additive monad is weaker...
-
- // zero is a monadic zero
- Monad.assertZero(zero);
-
- // left zero: zero >>= f === zero
- Monad.assertZero(zero.thenCompose(inc));
- // right zero: f >>= (\x -> zero) === zero
- Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero));
-
- // f plus zero === f
- Monad.assertFutureEquals(Monad.unit(5L),
- Monad.plus(Monad.unit(5L), zero));
- // zero plus f === f
- Monad.assertFutureEquals(Monad.unit(5L),
- Monad.plus(zero, Monad.unit(5L)));
- // zero plus zero === zero
- Monad.assertZero(Monad.plus(zero, zero));
- {
- CompletableFuture<Long> f = Monad.plus(Monad.unit(5L),
- Monad.unit(8L));
- // non-determinism
- assertTrue(f.get() == 5L || f.get() == 8L);
- }
-
- CompletableFuture<Long> godot = new CompletableFuture<>();
- // f plus godot === f (doesn't wait for godot)
- Monad.assertFutureEquals(Monad.unit(5L),
- Monad.plus(Monad.unit(5L), godot));
- // godot plus f === f (doesn't wait for godot)
- Monad.assertFutureEquals(Monad.unit(5L),
- Monad.plus(godot, Monad.unit(5L)));
- }
-
-// static <U> U join(CompletionStage<U> stage) {
-// CompletableFuture<U> f = new CompletableFuture<>();
-// stage.whenComplete((v, ex) -> {
-// if (ex != null) f.completeExceptionally(ex); else f.complete(v);
-// });
-// return f.join();
-// }
-
-// static <U> boolean isDone(CompletionStage<U> stage) {
-// CompletableFuture<U> f = new CompletableFuture<>();
-// stage.whenComplete((v, ex) -> {
-// if (ex != null) f.completeExceptionally(ex); else f.complete(v);
-// });
-// return f.isDone();
-// }
-
-// static <U> U join2(CompletionStage<U> stage) {
-// return stage.toCompletableFuture().copy().join();
-// }
-
-// static <U> boolean isDone2(CompletionStage<U> stage) {
-// return stage.toCompletableFuture().copy().isDone();
-// }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java
deleted file mode 100644
index 60de8b9..0000000
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.Spliterator.CONCURRENT;
-import static java.util.Spliterator.DISTINCT;
-import static java.util.Spliterator.NONNULL;
-
-import java.util.AbstractMap;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.LongAdder;
-import java.util.function.BiFunction;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class ConcurrentHashMap8Test extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(ConcurrentHashMap8Test.class);
- // }
-
- /**
- * Returns a new map from Integers 1-5 to Strings "A"-"E".
- */
- private static ConcurrentHashMap map5() {
- ConcurrentHashMap map = new ConcurrentHashMap(5);
- assertTrue(map.isEmpty());
- map.put(one, "A");
- map.put(two, "B");
- map.put(three, "C");
- map.put(four, "D");
- map.put(five, "E");
- assertFalse(map.isEmpty());
- assertEquals(5, map.size());
- return map;
- }
-
- /**
- * getOrDefault returns value if present, else default
- */
- public void testGetOrDefault() {
- ConcurrentHashMap map = map5();
- assertEquals(map.getOrDefault(one, "Z"), "A");
- assertEquals(map.getOrDefault(six, "Z"), "Z");
- }
-
- /**
- * computeIfAbsent adds when the given key is not present
- */
- public void testComputeIfAbsent() {
- ConcurrentHashMap map = map5();
- map.computeIfAbsent(six, (x) -> "Z");
- assertTrue(map.containsKey(six));
- }
-
- /**
- * computeIfAbsent does not replace if the key is already present
- */
- public void testComputeIfAbsent2() {
- ConcurrentHashMap map = map5();
- assertEquals("A", map.computeIfAbsent(one, (x) -> "Z"));
- }
-
- /**
- * computeIfAbsent does not add if function returns null
- */
- public void testComputeIfAbsent3() {
- ConcurrentHashMap map = map5();
- map.computeIfAbsent(six, (x) -> null);
- assertFalse(map.containsKey(six));
- }
-
- /**
- * computeIfPresent does not replace if the key is already present
- */
- public void testComputeIfPresent() {
- ConcurrentHashMap map = map5();
- map.computeIfPresent(six, (x, y) -> "Z");
- assertFalse(map.containsKey(six));
- }
-
- /**
- * computeIfPresent adds when the given key is not present
- */
- public void testComputeIfPresent2() {
- ConcurrentHashMap map = map5();
- assertEquals("Z", map.computeIfPresent(one, (x, y) -> "Z"));
- }
-
- /**
- * compute does not replace if the function returns null
- */
- public void testCompute() {
- ConcurrentHashMap map = map5();
- map.compute(six, (x, y) -> null);
- assertFalse(map.containsKey(six));
- }
-
- /**
- * compute adds when the given key is not present
- */
- public void testCompute2() {
- ConcurrentHashMap map = map5();
- assertEquals("Z", map.compute(six, (x, y) -> "Z"));
- }
-
- /**
- * compute replaces when the given key is present
- */
- public void testCompute3() {
- ConcurrentHashMap map = map5();
- assertEquals("Z", map.compute(one, (x, y) -> "Z"));
- }
-
- /**
- * compute removes when the given key is present and function returns null
- */
- public void testCompute4() {
- ConcurrentHashMap map = map5();
- map.compute(one, (x, y) -> null);
- assertFalse(map.containsKey(one));
- }
-
- /**
- * merge adds when the given key is not present
- */
- public void testMerge1() {
- ConcurrentHashMap map = map5();
- assertEquals("Y", map.merge(six, "Y", (x, y) -> "Z"));
- }
-
- /**
- * merge replaces when the given key is present
- */
- public void testMerge2() {
- ConcurrentHashMap map = map5();
- assertEquals("Z", map.merge(one, "Y", (x, y) -> "Z"));
- }
-
- /**
- * merge removes when the given key is present and function returns null
- */
- public void testMerge3() {
- ConcurrentHashMap map = map5();
- map.merge(one, "Y", (x, y) -> null);
- assertFalse(map.containsKey(one));
- }
-
- static Set<Integer> populatedSet(int n) {
- Set<Integer> a = ConcurrentHashMap.<Integer>newKeySet();
- assertTrue(a.isEmpty());
- for (int i = 0; i < n; i++)
- assertTrue(a.add(i));
- assertEquals(n == 0, a.isEmpty());
- assertEquals(n, a.size());
- return a;
- }
-
- static Set populatedSet(Integer[] elements) {
- Set<Integer> a = ConcurrentHashMap.<Integer>newKeySet();
- assertTrue(a.isEmpty());
- for (int i = 0; i < elements.length; i++)
- assertTrue(a.add(elements[i]));
- assertFalse(a.isEmpty());
- assertEquals(elements.length, a.size());
- return a;
- }
-
- /**
- * replaceAll replaces all matching values.
- */
- public void testReplaceAll() {
- ConcurrentHashMap<Integer, String> map = map5();
- map.replaceAll((x, y) -> { return x > 3 ? "Z" : y; });
- assertEquals("A", map.get(one));
- assertEquals("B", map.get(two));
- assertEquals("C", map.get(three));
- assertEquals("Z", map.get(four));
- assertEquals("Z", map.get(five));
- }
-
- /**
- * Default-constructed set is empty
- */
- public void testNewKeySet() {
- Set a = ConcurrentHashMap.newKeySet();
- assertTrue(a.isEmpty());
- }
-
- /**
- * keySet.add adds the key with the established value to the map;
- * remove removes it.
- */
- public void testKeySetAddRemove() {
- ConcurrentHashMap map = map5();
- Set set1 = map.keySet();
- Set set2 = map.keySet(true);
- set2.add(six);
- assertTrue(((ConcurrentHashMap.KeySetView)set2).getMap() == map);
- assertTrue(((ConcurrentHashMap.KeySetView)set1).getMap() == map);
- assertEquals(set2.size(), map.size());
- assertEquals(set1.size(), map.size());
- assertTrue((Boolean)map.get(six));
- assertTrue(set1.contains(six));
- assertTrue(set2.contains(six));
- set2.remove(six);
- assertNull(map.get(six));
- assertFalse(set1.contains(six));
- assertFalse(set2.contains(six));
- }
-
- /**
- * keySet.addAll adds each element from the given collection
- */
- public void testAddAll() {
- Set full = populatedSet(3);
- assertTrue(full.addAll(Arrays.asList(three, four, five)));
- assertEquals(6, full.size());
- assertFalse(full.addAll(Arrays.asList(three, four, five)));
- assertEquals(6, full.size());
- }
-
- /**
- * keySet.addAll adds each element from the given collection that did not
- * already exist in the set
- */
- public void testAddAll2() {
- Set full = populatedSet(3);
- // "one" is duplicate and will not be added
- assertTrue(full.addAll(Arrays.asList(three, four, one)));
- assertEquals(5, full.size());
- assertFalse(full.addAll(Arrays.asList(three, four, one)));
- assertEquals(5, full.size());
- }
-
- /**
- * keySet.add will not add the element if it already exists in the set
- */
- public void testAdd2() {
- Set full = populatedSet(3);
- assertFalse(full.add(one));
- assertEquals(3, full.size());
- }
-
- /**
- * keySet.add adds the element when it does not exist in the set
- */
- public void testAdd3() {
- Set full = populatedSet(3);
- assertTrue(full.add(three));
- assertTrue(full.contains(three));
- assertFalse(full.add(three));
- assertTrue(full.contains(three));
- }
-
- /**
- * keySet.add throws UnsupportedOperationException if no default
- * mapped value
- */
- public void testAdd4() {
- Set full = map5().keySet();
- try {
- full.add(three);
- shouldThrow();
- } catch (UnsupportedOperationException success) {}
- }
-
- /**
- * keySet.add throws NullPointerException if the specified key is
- * null
- */
- public void testAdd5() {
- Set full = populatedSet(3);
- try {
- full.add(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
-
- /**
- * KeySetView.getMappedValue returns the map's mapped value
- */
- public void testGetMappedValue() {
- ConcurrentHashMap map = map5();
- assertNull(map.keySet().getMappedValue());
- try {
- map.keySet(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- ConcurrentHashMap.KeySetView set = map.keySet(one);
- assertFalse(set.add(one));
- assertTrue(set.add(six));
- assertTrue(set.add(seven));
- assertTrue(set.getMappedValue() == one);
- assertTrue(map.get(one) != one);
- assertTrue(map.get(six) == one);
- assertTrue(map.get(seven) == one);
- }
-
- void checkSpliteratorCharacteristics(Spliterator<?> sp,
- int requiredCharacteristics) {
- assertEquals(requiredCharacteristics,
- requiredCharacteristics & sp.characteristics());
- }
-
- /**
- * KeySetView.spliterator returns spliterator over the elements in this set
- */
- public void testKeySetSpliterator() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap map = map5();
- Set set = map.keySet();
- Spliterator<Integer> sp = set.spliterator();
- checkSpliteratorCharacteristics(sp, CONCURRENT | DISTINCT | NONNULL);
- assertEquals(sp.estimateSize(), map.size());
- Spliterator<Integer> sp2 = sp.trySplit();
- sp.forEachRemaining((Integer x) -> adder.add(x.longValue()));
- long v = adder.sumThenReset();
- sp2.forEachRemaining((Integer x) -> adder.add(x.longValue()));
- long v2 = adder.sum();
- assertEquals(v + v2, 15);
- }
-
- /**
- * keyset.clear removes all elements from the set
- */
- public void testClear() {
- Set full = populatedSet(3);
- full.clear();
- assertEquals(0, full.size());
- }
-
- /**
- * keyset.contains returns true for added elements
- */
- public void testContains() {
- Set full = populatedSet(3);
- assertTrue(full.contains(one));
- assertFalse(full.contains(five));
- }
-
- /**
- * KeySets with equal elements are equal
- */
- public void testEquals() {
- Set a = populatedSet(3);
- Set b = populatedSet(3);
- assertTrue(a.equals(b));
- assertTrue(b.equals(a));
- assertEquals(a.hashCode(), b.hashCode());
- a.add(m1);
- assertFalse(a.equals(b));
- assertFalse(b.equals(a));
- b.add(m1);
- assertTrue(a.equals(b));
- assertTrue(b.equals(a));
- assertEquals(a.hashCode(), b.hashCode());
- }
-
- /**
- * KeySet.containsAll returns true for collections with subset of elements
- */
- public void testContainsAll() {
- Collection full = populatedSet(3);
- assertTrue(full.containsAll(Arrays.asList()));
- assertTrue(full.containsAll(Arrays.asList(one)));
- assertTrue(full.containsAll(Arrays.asList(one, two)));
- assertFalse(full.containsAll(Arrays.asList(one, two, six)));
- assertFalse(full.containsAll(Arrays.asList(six)));
- }
-
- /**
- * KeySet.isEmpty is true when empty, else false
- */
- public void testIsEmpty() {
- assertTrue(populatedSet(0).isEmpty());
- assertFalse(populatedSet(3).isEmpty());
- }
-
- /**
- * KeySet.iterator() returns an iterator containing the elements of the
- * set
- */
- public void testIterator() {
- Collection empty = ConcurrentHashMap.newKeySet();
- int size = 20;
- assertFalse(empty.iterator().hasNext());
- try {
- empty.iterator().next();
- shouldThrow();
- } catch (NoSuchElementException success) {}
-
- Integer[] elements = new Integer[size];
- for (int i = 0; i < size; i++)
- elements[i] = i;
- Collections.shuffle(Arrays.asList(elements));
- Collection<Integer> full = populatedSet(elements);
-
- Iterator it = full.iterator();
- for (int j = 0; j < size; j++) {
- assertTrue(it.hasNext());
- it.next();
- }
- assertIteratorExhausted(it);
- }
-
- /**
- * iterator of empty collections has no elements
- */
- public void testEmptyIterator() {
- assertIteratorExhausted(ConcurrentHashMap.newKeySet().iterator());
- assertIteratorExhausted(new ConcurrentHashMap().entrySet().iterator());
- assertIteratorExhausted(new ConcurrentHashMap().values().iterator());
- assertIteratorExhausted(new ConcurrentHashMap().keySet().iterator());
- }
-
- /**
- * KeySet.iterator.remove removes current element
- */
- public void testIteratorRemove() {
- Set q = populatedSet(3);
- Iterator it = q.iterator();
- Object removed = it.next();
- it.remove();
-
- it = q.iterator();
- assertFalse(it.next().equals(removed));
- assertFalse(it.next().equals(removed));
- assertFalse(it.hasNext());
- }
-
- /**
- * KeySet.toString holds toString of elements
- */
- public void testToString() {
- assertEquals("[]", ConcurrentHashMap.newKeySet().toString());
- Set full = populatedSet(3);
- String s = full.toString();
- for (int i = 0; i < 3; ++i)
- assertTrue(s.contains(String.valueOf(i)));
- }
-
- /**
- * KeySet.removeAll removes all elements from the given collection
- */
- public void testRemoveAll() {
- Set full = populatedSet(3);
- assertTrue(full.removeAll(Arrays.asList(one, two)));
- assertEquals(1, full.size());
- assertFalse(full.removeAll(Arrays.asList(one, two)));
- assertEquals(1, full.size());
- }
-
- /**
- * KeySet.remove removes an element
- */
- public void testRemove() {
- Set full = populatedSet(3);
- full.remove(one);
- assertFalse(full.contains(one));
- assertEquals(2, full.size());
- }
-
- /**
- * keySet.size returns the number of elements
- */
- public void testSize() {
- Set empty = ConcurrentHashMap.newKeySet();
- Set full = populatedSet(3);
- assertEquals(3, full.size());
- assertEquals(0, empty.size());
- }
-
- /**
- * KeySet.toArray() returns an Object array containing all elements from
- * the set
- */
- public void testToArray() {
- Object[] a = ConcurrentHashMap.newKeySet().toArray();
- assertTrue(Arrays.equals(new Object[0], a));
- assertSame(Object[].class, a.getClass());
- int size = 20;
- Integer[] elements = new Integer[size];
- for (int i = 0; i < size; i++)
- elements[i] = i;
- Collections.shuffle(Arrays.asList(elements));
- Collection<Integer> full = populatedSet(elements);
-
- assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray())));
- assertTrue(full.containsAll(Arrays.asList(full.toArray())));
- assertSame(Object[].class, full.toArray().getClass());
- }
-
- /**
- * toArray(Integer array) returns an Integer array containing all
- * elements from the set
- */
- public void testToArray2() {
- Collection empty = ConcurrentHashMap.newKeySet();
- Integer[] a;
- int size = 20;
-
- a = new Integer[0];
- assertSame(a, empty.toArray(a));
-
- a = new Integer[size / 2];
- Arrays.fill(a, 42);
- assertSame(a, empty.toArray(a));
- assertNull(a[0]);
- for (int i = 1; i < a.length; i++)
- assertEquals(42, (int) a[i]);
-
- Integer[] elements = new Integer[size];
- for (int i = 0; i < size; i++)
- elements[i] = i;
- Collections.shuffle(Arrays.asList(elements));
- Collection<Integer> full = populatedSet(elements);
-
- Arrays.fill(a, 42);
- assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray(a))));
- for (int i = 0; i < a.length; i++)
- assertEquals(42, (int) a[i]);
- assertSame(Integer[].class, full.toArray(a).getClass());
-
- a = new Integer[size];
- Arrays.fill(a, 42);
- assertSame(a, full.toArray(a));
- assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray(a))));
- }
-
- /**
- * A deserialized serialized set is equal
- */
- public void testSerialization() throws Exception {
- int size = 20;
- Set x = populatedSet(size);
- Set y = serialClone(x);
-
- assertNotSame(x, y);
- assertEquals(x.size(), y.size());
- assertEquals(x, y);
- assertEquals(y, x);
- }
-
- static final int SIZE = 10000;
- static ConcurrentHashMap<Long, Long> longMap;
-
- static ConcurrentHashMap<Long, Long> longMap() {
- if (longMap == null) {
- longMap = new ConcurrentHashMap<Long, Long>(SIZE);
- for (int i = 0; i < SIZE; ++i)
- longMap.put(Long.valueOf(i), Long.valueOf(2 *i));
- }
- return longMap;
- }
-
- // explicit function class to avoid type inference problems
- static class AddKeys implements BiFunction<Map.Entry<Long,Long>, Map.Entry<Long,Long>, Map.Entry<Long,Long>> {
- public Map.Entry<Long,Long> apply(Map.Entry<Long,Long> x, Map.Entry<Long,Long> y) {
- return new AbstractMap.SimpleEntry<Long,Long>
- (Long.valueOf(x.getKey().longValue() + y.getKey().longValue()),
- Long.valueOf(1L));
- }
- }
-
- /**
- * forEachKeySequentially traverses all keys
- */
- public void testForEachKeySequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachKey(Long.MAX_VALUE, (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * forEachValueSequentially traverses all values
- */
- public void testForEachValueSequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachValue(Long.MAX_VALUE, (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), SIZE * (SIZE - 1));
- }
-
- /**
- * forEachSequentially traverses all mappings
- */
- public void testForEachSequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEach(Long.MAX_VALUE, (Long x, Long y) -> adder.add(x.longValue() + y.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * forEachEntrySequentially traverses all entries
- */
- public void testForEachEntrySequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachEntry(Long.MAX_VALUE, (Map.Entry<Long,Long> e) -> adder.add(e.getKey().longValue() + e.getValue().longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * forEachKeyInParallel traverses all keys
- */
- public void testForEachKeyInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachKey(1L, (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * forEachValueInParallel traverses all values
- */
- public void testForEachValueInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachValue(1L, (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), SIZE * (SIZE - 1));
- }
-
- /**
- * forEachInParallel traverses all mappings
- */
- public void testForEachInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEach(1L, (Long x, Long y) -> adder.add(x.longValue() + y.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * forEachEntryInParallel traverses all entries
- */
- public void testForEachEntryInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachEntry(1L, (Map.Entry<Long,Long> e) -> adder.add(e.getKey().longValue() + e.getValue().longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachKeySequentially traverses the given
- * transformations of all keys
- */
- public void testMappedForEachKeySequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachKey(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachValueSequentially traverses the given
- * transformations of all values
- */
- public void testMappedForEachValueSequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachValue(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1));
- }
-
- /**
- * Mapped forEachSequentially traverses the given
- * transformations of all mappings
- */
- public void testMappedForEachSequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEach(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachEntrySequentially traverses the given
- * transformations of all entries
- */
- public void testMappedForEachEntrySequentially() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachEntry(Long.MAX_VALUE, (Map.Entry<Long,Long> e) -> Long.valueOf(e.getKey().longValue() + e.getValue().longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachKeyInParallel traverses the given
- * transformations of all keys
- */
- public void testMappedForEachKeyInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachKey(1L, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachValueInParallel traverses the given
- * transformations of all values
- */
- public void testMappedForEachValueInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachValue(1L, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1));
- }
-
- /**
- * Mapped forEachInParallel traverses the given
- * transformations of all mappings
- */
- public void testMappedForEachInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEach(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped forEachEntryInParallel traverses the given
- * transformations of all entries
- */
- public void testMappedForEachEntryInParallel() {
- LongAdder adder = new LongAdder();
- ConcurrentHashMap<Long, Long> m = longMap();
- m.forEachEntry(1L, (Map.Entry<Long,Long> e) -> Long.valueOf(e.getKey().longValue() + e.getValue().longValue()),
- (Long x) -> adder.add(x.longValue()));
- assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysSequentially accumulates across all keys,
- */
- public void testReduceKeysSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.reduceKeys(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceValuesSequentially accumulates across all values
- */
- public void testReduceValuesSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.reduceKeys(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceEntriesSequentially accumulates across all entries
- */
- public void testReduceEntriesSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Map.Entry<Long,Long> r;
- r = m.reduceEntries(Long.MAX_VALUE, new AddKeys());
- assertEquals(r.getKey().longValue(), (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysInParallel accumulates across all keys
- */
- public void testReduceKeysInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.reduceKeys(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceValuesInParallel accumulates across all values
- */
- public void testReduceValuesInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.reduceValues(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)SIZE * (SIZE - 1));
- }
-
- /**
- * reduceEntriesInParallel accumulate across all entries
- */
- public void testReduceEntriesInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Map.Entry<Long,Long> r;
- r = m.reduceEntries(1L, new AddKeys());
- assertEquals(r.getKey().longValue(), (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped reduceKeysSequentially accumulates mapped keys
- */
- public void testMapReduceKeysSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r = m.reduceKeys(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)4 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped reduceValuesSequentially accumulates mapped values
- */
- public void testMapReduceValuesSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r = m.reduceValues(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)4 * SIZE * (SIZE - 1));
- }
-
- /**
- * reduceSequentially accumulates across all transformed mappings
- */
- public void testMappedReduceSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r = m.reduce(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
-
- assertEquals((long)r, (long)3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped reduceKeysInParallel, accumulates mapped keys
- */
- public void testMapReduceKeysInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r = m.reduceKeys(1L, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)4 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * Mapped reduceValuesInParallel accumulates mapped values
- */
- public void testMapReduceValuesInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r = m.reduceValues(1L, (Long x) -> Long.valueOf(4 * x.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)4 * SIZE * (SIZE - 1));
- }
-
- /**
- * reduceInParallel accumulate across all transformed mappings
- */
- public void testMappedReduceInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.reduce(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()),
- (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()));
- assertEquals((long)r, (long)3 * SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysToLongSequentially accumulates mapped keys
- */
- public void testReduceKeysToLongSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- long lr = m.reduceKeysToLong(Long.MAX_VALUE, (Long x) -> x.longValue(), 0L, Long::sum);
- assertEquals(lr, (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysToIntSequentially accumulates mapped keys
- */
- public void testReduceKeysToIntSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- int ir = m.reduceKeysToInt(Long.MAX_VALUE, (Long x) -> x.intValue(), 0, Integer::sum);
- assertEquals(ir, SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysToDoubleSequentially accumulates mapped keys
- */
- public void testReduceKeysToDoubleSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- double dr = m.reduceKeysToDouble(Long.MAX_VALUE, (Long x) -> x.doubleValue(), 0.0, Double::sum);
- assertEquals(dr, (double)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceValuesToLongSequentially accumulates mapped values
- */
- public void testReduceValuesToLongSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- long lr = m.reduceValuesToLong(Long.MAX_VALUE, (Long x) -> x.longValue(), 0L, Long::sum);
- assertEquals(lr, (long)SIZE * (SIZE - 1));
- }
-
- /**
- * reduceValuesToIntSequentially accumulates mapped values
- */
- public void testReduceValuesToIntSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- int ir = m.reduceValuesToInt(Long.MAX_VALUE, (Long x) -> x.intValue(), 0, Integer::sum);
- assertEquals(ir, SIZE * (SIZE - 1));
- }
-
- /**
- * reduceValuesToDoubleSequentially accumulates mapped values
- */
- public void testReduceValuesToDoubleSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- double dr = m.reduceValuesToDouble(Long.MAX_VALUE, (Long x) -> x.doubleValue(), 0.0, Double::sum);
- assertEquals(dr, (double)SIZE * (SIZE - 1));
- }
-
- /**
- * reduceKeysToLongInParallel accumulates mapped keys
- */
- public void testReduceKeysToLongInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- long lr = m.reduceKeysToLong(1L, (Long x) -> x.longValue(), 0L, Long::sum);
- assertEquals(lr, (long)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysToIntInParallel accumulates mapped keys
- */
- public void testReduceKeysToIntInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- int ir = m.reduceKeysToInt(1L, (Long x) -> x.intValue(), 0, Integer::sum);
- assertEquals(ir, SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceKeysToDoubleInParallel accumulates mapped values
- */
- public void testReduceKeysToDoubleInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- double dr = m.reduceKeysToDouble(1L, (Long x) -> x.doubleValue(), 0.0, Double::sum);
- assertEquals(dr, (double)SIZE * (SIZE - 1) / 2);
- }
-
- /**
- * reduceValuesToLongInParallel accumulates mapped values
- */
- public void testReduceValuesToLongInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- long lr = m.reduceValuesToLong(1L, (Long x) -> x.longValue(), 0L, Long::sum);
- assertEquals(lr, (long)SIZE * (SIZE - 1));
- }
-
- /**
- * reduceValuesToIntInParallel accumulates mapped values
- */
- public void testReduceValuesToIntInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- int ir = m.reduceValuesToInt(1L, (Long x) -> x.intValue(), 0, Integer::sum);
- assertEquals(ir, SIZE * (SIZE - 1));
- }
-
- /**
- * reduceValuesToDoubleInParallel accumulates mapped values
- */
- public void testReduceValuesToDoubleInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- double dr = m.reduceValuesToDouble(1L, (Long x) -> x.doubleValue(), 0.0, Double::sum);
- assertEquals(dr, (double)SIZE * (SIZE - 1));
- }
-
- /**
- * searchKeysSequentially returns a non-null result of search
- * function, or null if none
- */
- public void testSearchKeysSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchKeys(Long.MAX_VALUE, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchKeys(Long.MAX_VALUE, (Long x) -> x.longValue() < 0L ? x : null);
- assertNull(r);
- }
-
- /**
- * searchValuesSequentially returns a non-null result of search
- * function, or null if none
- */
- public void testSearchValuesSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchValues(Long.MAX_VALUE,
- (Long x) -> (x.longValue() == (long)(SIZE/2)) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchValues(Long.MAX_VALUE,
- (Long x) -> (x.longValue() < 0L) ? x : null);
- assertNull(r);
- }
-
- /**
- * searchSequentially returns a non-null result of search
- * function, or null if none
- */
- public void testSearchSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.search(Long.MAX_VALUE, (Long x, Long y) -> x.longValue() == (long)(SIZE/2) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.search(Long.MAX_VALUE, (Long x, Long y) -> x.longValue() < 0L ? x : null);
- assertNull(r);
- }
-
- /**
- * searchEntriesSequentially returns a non-null result of search
- * function, or null if none
- */
- public void testSearchEntriesSequentially() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchEntries(Long.MAX_VALUE, (Map.Entry<Long,Long> e) -> e.getKey().longValue() == (long)(SIZE/2) ? e.getKey() : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchEntries(Long.MAX_VALUE, (Map.Entry<Long,Long> e) -> e.getKey().longValue() < 0L ? e.getKey() : null);
- assertNull(r);
- }
-
- /**
- * searchKeysInParallel returns a non-null result of search
- * function, or null if none
- */
- public void testSearchKeysInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchKeys(1L, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchKeys(1L, (Long x) -> x.longValue() < 0L ? x : null);
- assertNull(r);
- }
-
- /**
- * searchValuesInParallel returns a non-null result of search
- * function, or null if none
- */
- public void testSearchValuesInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchValues(1L, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchValues(1L, (Long x) -> x.longValue() < 0L ? x : null);
- assertNull(r);
- }
-
- /**
- * searchInParallel returns a non-null result of search function,
- * or null if none
- */
- public void testSearchInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.search(1L, (Long x, Long y) -> x.longValue() == (long)(SIZE/2) ? x : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.search(1L, (Long x, Long y) -> x.longValue() < 0L ? x : null);
- assertNull(r);
- }
-
- /**
- * searchEntriesInParallel returns a non-null result of search
- * function, or null if none
- */
- public void testSearchEntriesInParallel() {
- ConcurrentHashMap<Long, Long> m = longMap();
- Long r;
- r = m.searchEntries(1L, (Map.Entry<Long,Long> e) -> e.getKey().longValue() == (long)(SIZE/2) ? e.getKey() : null);
- assertEquals((long)r, (long)(SIZE/2));
- r = m.searchEntries(1L, (Map.Entry<Long,Long> e) -> e.getKey().longValue() < 0L ? e.getKey() : null);
- assertNull(r);
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
index f427127..4650f41 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
@@ -30,7 +30,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentHashMapTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -50,9 +50,7 @@
}
/** Re-implement Integer.compare for old java versions */
- static int compare(int x, int y) {
- return (x < y) ? -1 : (x > y) ? 1 : 0;
- }
+ static int compare(int x, int y) { return x < y ? -1 : x > y ? 1 : 0; }
// classes for testing Comparable fallbacks
static class BI implements Comparable<BI> {
@@ -540,7 +538,7 @@
/**
* Constructor (initialCapacity, loadFactor) throws
* IllegalArgumentException if either argument is negative
- */
+ */
public void testConstructor2() {
try {
new ConcurrentHashMap(-1, .75f);
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
index 6625e7e..c445957 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentLinkedDequeTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -69,7 +69,8 @@
*/
public void testConstructor4() {
try {
- new ConcurrentLinkedDeque(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new ConcurrentLinkedDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -78,10 +79,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new ConcurrentLinkedDeque(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -119,7 +120,7 @@
public void testSize() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.remove();
}
for (int i = 0; i < SIZE; ++i) {
@@ -132,8 +133,8 @@
* push(null) throws NPE
*/
public void testPushNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.push(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -167,8 +168,8 @@
* offer(null) throws NPE
*/
public void testOfferNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.offer(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -178,8 +179,8 @@
* offerFirst(null) throws NPE
*/
public void testOfferFirstNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.offerFirst(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -189,8 +190,8 @@
* offerLast(null) throws NPE
*/
public void testOfferLastNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.offerLast(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -233,8 +234,8 @@
* add(null) throws NPE
*/
public void testAddNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -244,8 +245,8 @@
* addFirst(null) throws NPE
*/
public void testAddFirstNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.addFirst(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -255,8 +256,8 @@
* addLast(null) throws NPE
*/
public void testAddLastNull() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.addLast(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -299,8 +300,8 @@
* addAll(null) throws NPE
*/
public void testAddAll1() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -310,8 +311,8 @@
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
- ConcurrentLinkedDeque q = populatedDeque(SIZE);
try {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -321,9 +322,10 @@
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
try {
- q.addAll(Arrays.asList(new Integer[SIZE]));
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -333,11 +335,11 @@
* possibly adding some elements
*/
public void testAddAll3() {
- ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -374,7 +376,7 @@
*/
public void testPollLast() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollLast());
@@ -443,14 +445,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -474,7 +476,7 @@
*/
public void testPeekLast() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.peekLast());
assertEquals(i, q.pollLast());
assertTrue(q.peekLast() == null ||
@@ -503,7 +505,7 @@
*/
public void testLastElement() {
ConcurrentLinkedDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.getLast());
assertEquals(i, q.pollLast());
}
@@ -554,7 +556,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
- assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -569,7 +571,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
- assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -628,7 +630,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -641,7 +643,7 @@
ConcurrentLinkedDeque q = populatedDeque(SIZE);
ConcurrentLinkedDeque p = populatedDeque(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -757,18 +759,18 @@
final Random rng = new Random();
for (int iters = 0; iters < 100; ++iters) {
int max = rng.nextInt(5) + 2;
- int split = rng.nextInt(max - 1) + 1;
+ int split = rng.nextInt(max-1) + 1;
for (int j = 1; j <= max; ++j)
q.add(new Integer(j));
Iterator it = q.iterator();
for (int j = 1; j <= split; ++j)
assertEquals(it.next(), new Integer(j));
it.remove();
- assertEquals(it.next(), new Integer(split + 1));
+ assertEquals(it.next(), new Integer(split+1));
for (int j = 1; j <= split; ++j)
q.remove(new Integer(j));
it = q.iterator();
- for (int j = split + 1; j <= max; ++j) {
+ for (int j = split+1; j <= max; ++j) {
assertEquals(it.next(), new Integer(j));
it.remove();
}
@@ -825,18 +827,18 @@
final Random rng = new Random();
for (int iters = 0; iters < 100; ++iters) {
int max = rng.nextInt(5) + 2;
- int split = rng.nextInt(max - 1) + 1;
+ int split = rng.nextInt(max-1) + 1;
for (int j = max; j >= 1; --j)
q.add(new Integer(j));
Iterator it = q.descendingIterator();
for (int j = 1; j <= split; ++j)
assertEquals(it.next(), new Integer(j));
it.remove();
- assertEquals(it.next(), new Integer(split + 1));
+ assertEquals(it.next(), new Integer(split+1));
for (int j = 1; j <= split; ++j)
q.remove(new Integer(j));
it = q.descendingIterator();
- for (int j = split + 1; j <= max; ++j) {
+ for (int j = split+1; j <= max; ++j) {
assertEquals(it.next(), new Integer(j));
it.remove();
}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
index 70519a4..d3f5b1f 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
@@ -27,7 +27,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentLinkedQueueTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -66,7 +66,8 @@
*/
public void testConstructor4() {
try {
- new ConcurrentLinkedQueue(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new ConcurrentLinkedQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -75,10 +76,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new ConcurrentLinkedQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -116,7 +117,7 @@
public void testSize() {
ConcurrentLinkedQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.remove();
}
for (int i = 0; i < SIZE; ++i) {
@@ -129,8 +130,8 @@
* offer(null) throws NPE
*/
public void testOfferNull() {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
q.offer(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -140,8 +141,8 @@
* add(null) throws NPE
*/
public void testAddNull() {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -171,8 +172,8 @@
* addAll(null) throws NPE
*/
public void testAddAll1() {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -182,8 +183,8 @@
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
- ConcurrentLinkedQueue q = populatedQueue(SIZE);
try {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -193,9 +194,10 @@
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
try {
- q.addAll(Arrays.asList(new Integer[SIZE]));
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -205,11 +207,11 @@
* possibly adding some elements
*/
public void testAddAll3() {
- ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -293,14 +295,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -359,7 +361,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -372,7 +374,7 @@
ConcurrentLinkedQueue q = populatedQueue(SIZE);
ConcurrentLinkedQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
index f53a446..0aadd23 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
@@ -30,7 +30,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentSkipListMapTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -1278,7 +1278,7 @@
}
static boolean eq(Integer i, int j) {
- return (i == null) ? j == -1 : i == j;
+ return i == null ? j == -1 : i == j;
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
index 959d703..41f8835 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentSkipListSetTest.class);
+ // return new TestSuite(...);
// }
static class MyReverseComparator implements Comparator {
@@ -46,7 +46,7 @@
ConcurrentSkipListSet<Integer> q =
new ConcurrentSkipListSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
@@ -92,7 +92,8 @@
*/
public void testConstructor4() {
try {
- new ConcurrentSkipListSet(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new ConcurrentSkipListSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -101,10 +102,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new ConcurrentSkipListSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -133,7 +134,7 @@
for (int i = 0; i < SIZE; ++i)
ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
assertEquals(ints[i], q.pollFirst());
}
@@ -157,7 +158,7 @@
public void testSize() {
ConcurrentSkipListSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -237,7 +238,7 @@
public void testAddAll3() {
ConcurrentSkipListSet q = new ConcurrentSkipListSet();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
try {
q.addAll(Arrays.asList(ints));
@@ -252,7 +253,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1-i);
ConcurrentSkipListSet q = new ConcurrentSkipListSet();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -276,7 +277,7 @@
*/
public void testPollLast() {
ConcurrentSkipListSet q = populatedSet(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollFirst());
@@ -291,14 +292,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -357,7 +358,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -370,7 +371,7 @@
ConcurrentSkipListSet q = populatedSet(SIZE);
ConcurrentSkipListSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
@@ -979,7 +980,7 @@
}
static boolean eq(Integer i, int j) {
- return (i == null) ? j == -1 : i == j;
+ return i == null ? j == -1 : i == j;
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
index a6510f5..5315bcb 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
@@ -28,7 +28,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentSkipListSubMapTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
index 220a092..f1c4aae 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
@@ -24,7 +24,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ConcurrentSkipListSubSetTest.class);
+ // return new TestSuite(...);
// }
static class MyReverseComparator implements Comparator {
@@ -42,7 +42,7 @@
new ConcurrentSkipListSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
@@ -127,7 +127,7 @@
public void testSize() {
NavigableSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -206,8 +206,8 @@
public void testAddAll3() {
NavigableSet q = set0();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i + SIZE);
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
q.addAll(Arrays.asList(ints));
shouldThrow();
@@ -221,7 +221,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1- i);
NavigableSet q = set0();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -249,14 +249,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -315,7 +315,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -328,7 +328,7 @@
NavigableSet q = populatedSet(SIZE);
NavigableSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
@@ -623,7 +623,7 @@
public void testDescendingSize() {
NavigableSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -702,8 +702,8 @@
public void testDescendingAddAll3() {
NavigableSet q = dset0();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i + SIZE);
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
q.addAll(Arrays.asList(ints));
shouldThrow();
@@ -717,7 +717,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1- i);
NavigableSet q = dset0();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -746,7 +746,7 @@
}
for (int i = 0; i < SIZE; i += 2 ) {
assertTrue(q.remove(new Integer(i)));
- assertFalse(q.remove(new Integer(i + 1)));
+ assertFalse(q.remove(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -805,7 +805,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -818,7 +818,7 @@
NavigableSet q = populatedSet(SIZE);
NavigableSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
index 8a37d03..658268a 100644
--- a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
@@ -31,7 +31,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(CopyOnWriteArrayListTest.class);
+ // return new TestSuite(...);
// }
static CopyOnWriteArrayList<Integer> populatedArray(int n) {
@@ -67,7 +67,7 @@
*/
public void testConstructor2() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints);
for (int i = 0; i < SIZE; ++i)
@@ -79,7 +79,7 @@
*/
public void testConstructor3() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints));
for (int i = 0; i < SIZE; ++i)
@@ -181,26 +181,18 @@
CopyOnWriteArrayList b = populatedArray(3);
assertTrue(a.equals(b));
assertTrue(b.equals(a));
- assertTrue(a.containsAll(b));
- assertTrue(b.containsAll(a));
assertEquals(a.hashCode(), b.hashCode());
a.add(m1);
assertFalse(a.equals(b));
assertFalse(b.equals(a));
- assertTrue(a.containsAll(b));
- assertFalse(b.containsAll(a));
b.add(m1);
assertTrue(a.equals(b));
assertTrue(b.equals(a));
- assertTrue(a.containsAll(b));
- assertTrue(b.containsAll(a));
assertEquals(a.hashCode(), b.hashCode());
-
- assertFalse(a.equals(null));
}
/**
- * containsAll returns true for collections with subset of elements
+ * containsAll returns true for collection with subset of elements
*/
public void testContainsAll() {
CopyOnWriteArrayList full = populatedArray(3);
@@ -209,11 +201,6 @@
assertTrue(full.containsAll(Arrays.asList(one, two)));
assertFalse(full.containsAll(Arrays.asList(one, two, six)));
assertFalse(full.containsAll(Arrays.asList(six)));
-
- try {
- full.containsAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
}
/**
@@ -355,7 +342,7 @@
ListIterator i = full.listIterator(1);
int j;
for (j = 0; i.hasNext(); j++)
- assertEquals(j + 1, i.next());
+ assertEquals(j+1, i.next());
assertEquals(2, j);
}
@@ -454,7 +441,7 @@
a = new Integer[0];
assertSame(a, empty.toArray(a));
- a = new Integer[SIZE / 2];
+ a = new Integer[SIZE/2];
Arrays.fill(a, 42);
assertSame(a, empty.toArray(a));
assertNull(a[0]);
@@ -478,7 +465,7 @@
assertSame(a, full.toArray(a));
assertTrue(Arrays.equals(elements, a));
- a = new Integer[2 * SIZE];
+ a = new Integer[2*SIZE];
Arrays.fill(a, 42);
assertSame(a, full.toArray(a));
assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE)));
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
index a486c6a..2810802 100644
--- a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
@@ -28,7 +28,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(CopyOnWriteArraySetTest.class);
+ // return new TestSuite(...);
// }
static CopyOnWriteArraySet<Integer> populatedSet(int n) {
@@ -64,7 +64,7 @@
*/
public void testConstructor3() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
CopyOnWriteArraySet a = new CopyOnWriteArraySet(Arrays.asList(ints));
for (int i = 0; i < SIZE; ++i)
@@ -139,46 +139,14 @@
CopyOnWriteArraySet b = populatedSet(3);
assertTrue(a.equals(b));
assertTrue(b.equals(a));
- assertTrue(a.containsAll(b));
- assertTrue(b.containsAll(a));
assertEquals(a.hashCode(), b.hashCode());
- assertEquals(a.size(), b.size());
-
a.add(m1);
assertFalse(a.equals(b));
assertFalse(b.equals(a));
- assertTrue(a.containsAll(b));
- assertFalse(b.containsAll(a));
b.add(m1);
assertTrue(a.equals(b));
assertTrue(b.equals(a));
- assertTrue(a.containsAll(b));
- assertTrue(b.containsAll(a));
assertEquals(a.hashCode(), b.hashCode());
-
- Object x = a.iterator().next();
- a.remove(x);
- assertFalse(a.equals(b));
- assertFalse(b.equals(a));
- assertFalse(a.containsAll(b));
- assertTrue(b.containsAll(a));
- a.add(x);
- assertTrue(a.equals(b));
- assertTrue(b.equals(a));
- assertTrue(a.containsAll(b));
- assertTrue(b.containsAll(a));
- assertEquals(a.hashCode(), b.hashCode());
- assertEquals(a.size(), b.size());
-
- CopyOnWriteArraySet empty1 = new CopyOnWriteArraySet(Arrays.asList());
- CopyOnWriteArraySet empty2 = new CopyOnWriteArraySet(Arrays.asList());
- assertTrue(empty1.equals(empty1));
- assertTrue(empty1.equals(empty2));
-
- assertFalse(empty1.equals(a));
- assertFalse(a.equals(empty1));
-
- assertFalse(a.equals(null));
}
/**
@@ -186,24 +154,11 @@
*/
public void testContainsAll() {
Collection full = populatedSet(3);
- assertTrue(full.containsAll(full));
assertTrue(full.containsAll(Arrays.asList()));
assertTrue(full.containsAll(Arrays.asList(one)));
assertTrue(full.containsAll(Arrays.asList(one, two)));
assertFalse(full.containsAll(Arrays.asList(one, two, six)));
assertFalse(full.containsAll(Arrays.asList(six)));
-
- CopyOnWriteArraySet empty1 = new CopyOnWriteArraySet(Arrays.asList());
- CopyOnWriteArraySet empty2 = new CopyOnWriteArraySet(Arrays.asList());
- assertTrue(empty1.containsAll(empty2));
- assertTrue(empty1.containsAll(empty1));
- assertFalse(empty1.containsAll(full));
- assertTrue(full.containsAll(empty1));
-
- try {
- full.containsAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
}
/**
@@ -334,7 +289,7 @@
a = new Integer[0];
assertSame(a, empty.toArray(a));
- a = new Integer[SIZE / 2];
+ a = new Integer[SIZE/2];
Arrays.fill(a, 42);
assertSame(a, empty.toArray(a));
assertNull(a[0]);
@@ -358,7 +313,7 @@
assertSame(a, full.toArray(a));
assertTrue(Arrays.equals(elements, a));
- a = new Integer[2 * SIZE];
+ a = new Integer[2*SIZE];
Arrays.fill(a, 42);
assertSame(a, full.toArray(a));
assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE)));
@@ -372,10 +327,10 @@
* not store the objects inside the set
*/
public void testToArray_ArrayStoreException() {
- CopyOnWriteArraySet c = new CopyOnWriteArraySet();
- c.add("zfasdfsdf");
- c.add("asdadasd");
try {
+ CopyOnWriteArraySet c = new CopyOnWriteArraySet();
+ c.add("zfasdfsdf");
+ c.add("asdadasd");
c.toArray(new Long[5]);
shouldThrow();
} catch (ArrayStoreException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
index e764c9e..da1ebb4 100644
--- a/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
@@ -23,7 +23,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(CountDownLatchTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
index 8a38eff..80d7b3b 100644
--- a/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
@@ -31,7 +31,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(CountedCompleterTest.class);
+ // return new TestSuite(...);
// }
// Runs with "mainPool" use > 1 thread. singletonPool tests use 1
@@ -53,7 +53,7 @@
}
private void testInvokeOnPool(ForkJoinPool pool, ForkJoinTask a) {
- try (PoolCleaner cleaner = cleaner(pool)) {
+ try {
assertFalse(a.isDone());
assertFalse(a.isCompletedNormally());
assertFalse(a.isCompletedAbnormally());
@@ -69,6 +69,8 @@
assertFalse(a.isCancelled());
assertNull(a.getException());
assertNull(a.getRawResult());
+ } finally {
+ joinPool(pool);
}
}
@@ -97,17 +99,17 @@
{
Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
assertNull(a.join());
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
Thread.interrupted();
}
{
Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
Thread.interrupted();
}
@@ -140,9 +142,9 @@
Thread.interrupted();
{
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
try {
@@ -178,9 +180,9 @@
Thread.interrupted();
{
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
try {
@@ -282,9 +284,6 @@
final class NoopCC extends CheckedCC {
NoopCC() { super(); }
NoopCC(CountedCompleter p) { super(p); }
- NoopCC(CountedCompleter p, int initialPendingCount) {
- super(p, initialPendingCount);
- }
protected void realCompute() {}
}
@@ -303,7 +302,6 @@
void testComplete(NoopCC cc, Object x, int pendingCount) {
cc.setPendingCount(pendingCount);
cc.checkCompletes(x);
- assertEquals(pendingCount, cc.getPendingCount());
}
/**
@@ -317,20 +315,14 @@
}
/**
- * completeExceptionally(null) surprisingly has the same effect as
- * completeExceptionally(new RuntimeException())
+ * completeExceptionally(null) throws NullPointerException
*/
public void testCompleteExceptionally_null() {
- NoopCC a = new NoopCC();
- a.completeExceptionally(null);
try {
- a.invoke();
+ new NoopCC()
+ .checkCompletesExceptionally(null);
shouldThrow();
- } catch (RuntimeException success) {
- assertSame(success.getClass(), RuntimeException.class);
- assertNull(success.getCause());
- a.checkCompletedExceptionally(success);
- }
+ } catch (NullPointerException success) {}
}
/**
@@ -339,15 +331,10 @@
public void testSetPendingCount() {
NoopCC a = new NoopCC();
assertEquals(0, a.getPendingCount());
- int[] vals = {
- -1, 0, 1,
- Integer.MIN_VALUE,
- Integer.MAX_VALUE,
- };
- for (int val : vals) {
- a.setPendingCount(val);
- assertEquals(val, a.getPendingCount());
- }
+ a.setPendingCount(1);
+ assertEquals(1, a.getPendingCount());
+ a.setPendingCount(27);
+ assertEquals(27, a.getPendingCount());
}
/**
@@ -360,26 +347,21 @@
assertEquals(1, a.getPendingCount());
a.addToPendingCount(27);
assertEquals(28, a.getPendingCount());
- a.addToPendingCount(-28);
- assertEquals(0, a.getPendingCount());
}
/**
* decrementPendingCountUnlessZero decrements reported pending
* count unless zero
*/
- public void testDecrementPendingCountUnlessZero() {
- NoopCC a = new NoopCC(null, 2);
- assertEquals(2, a.getPendingCount());
- assertEquals(2, a.decrementPendingCountUnlessZero());
+ public void testDecrementPendingCount() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ a.addToPendingCount(1);
assertEquals(1, a.getPendingCount());
- assertEquals(1, a.decrementPendingCountUnlessZero());
+ a.decrementPendingCountUnlessZero();
assertEquals(0, a.getPendingCount());
- assertEquals(0, a.decrementPendingCountUnlessZero());
+ a.decrementPendingCountUnlessZero();
assertEquals(0, a.getPendingCount());
- a.setPendingCount(-1);
- assertEquals(-1, a.decrementPendingCountUnlessZero());
- assertEquals(-2, a.getPendingCount());
}
/**
@@ -503,7 +485,7 @@
}
/**
- * quietlyCompleteRoot completes root task and only root task
+ * quietlyCompleteRoot completes root task
*/
public void testQuietlyCompleteRoot() {
NoopCC a = new NoopCC();
diff --git a/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
index 37adcb1..a9d8c54 100644
--- a/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
@@ -27,7 +27,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(CyclicBarrierTest.class);
+ // return new TestSuite(...);
// }
private volatile int countAction;
diff --git a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
index e42ac2d..7619b48 100644
--- a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
@@ -25,26 +25,25 @@
import junit.framework.Test;
-public class DelayQueueTest extends JSR166TestCase {
+// android-changed: Extend BlockingQueueTest directly.
+public class DelayQueueTest extends BlockingQueueTest {
// android-changed: Extend BlockingQueueTest directly instead of creating
// an inner class and its associated suite.
//
// public static class Generic extends BlockingQueueTest {
- // protected BlockingQueue emptyCollection() {
+ // protected BlockingQueue emptyCollection() {
// return new DelayQueue();
// }
// protected PDelay makeElement(int i) {
// return new PDelay(i);
// }
// }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(DelayQueueTest.class,
// new Generic().testSuite());
@@ -139,7 +138,7 @@
private DelayQueue<PDelay> populatedQueue(int n) {
DelayQueue<PDelay> q = new DelayQueue<PDelay>();
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new PDelay(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new PDelay(i)));
@@ -171,7 +170,8 @@
*/
public void testConstructor4() {
try {
- new DelayQueue(Arrays.asList(new PDelay[SIZE]));
+ PDelay[] ints = new PDelay[SIZE];
+ new DelayQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -180,11 +180,11 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- PDelay[] a = new PDelay[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- a[i] = new PDelay(i);
try {
- new DelayQueue(Arrays.asList(a));
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new PDelay(i);
+ new DelayQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -223,7 +223,7 @@
BlockingQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
assertTrue(q.remove() instanceof PDelay);
}
for (int i = 0; i < SIZE; ++i) {
@@ -257,8 +257,8 @@
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
- DelayQueue q = populatedQueue(SIZE);
try {
+ DelayQueue q = populatedQueue(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -269,12 +269,12 @@
* possibly adding some elements
*/
public void testAddAll3() {
- DelayQueue q = new DelayQueue();
- PDelay[] a = new PDelay[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- a[i] = new PDelay(i);
try {
- q.addAll(Arrays.asList(a));
+ DelayQueue q = new DelayQueue();
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new PDelay(i);
+ q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -285,7 +285,7 @@
public void testAddAll5() {
PDelay[] empty = new PDelay[0];
PDelay[] ints = new PDelay[SIZE];
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
ints[i] = new PDelay(i);
DelayQueue q = new DelayQueue();
assertFalse(q.addAll(Arrays.asList(empty)));
@@ -427,13 +427,11 @@
*/
public void testInterruptedTimedPoll() throws InterruptedException {
final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
- final DelayQueue q = populatedQueue(SIZE);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
+ DelayQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(new PDelay(i),
- ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS)));
+ assertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, MILLISECONDS)));
}
Thread.currentThread().interrupt();
@@ -449,14 +447,12 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
await(pleaseInterrupt);
assertThreadStaysAlive(t);
t.interrupt();
awaitTermination(t);
- checkEmpty(q);
}
/**
@@ -561,7 +557,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -574,7 +570,7 @@
DelayQueue q = populatedQueue(SIZE);
DelayQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
PDelay x = (PDelay)(p.remove());
assertFalse(q.contains(x));
@@ -672,22 +668,22 @@
public void testPollInExecutor() {
final DelayQueue q = new DelayQueue();
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertNotNull(q.poll(LONG_DELAY_MS, MILLISECONDS));
- checkEmpty(q);
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertNotNull(q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(new PDelay(1));
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(new PDelay(1));
+ }});
+
+ joinPool(executor);
}
/**
@@ -772,7 +768,7 @@
final DelayQueue q = populatedQueue(SIZE);
Thread t = new Thread(new CheckedRunnable() {
public void realRun() {
- q.put(new PDelay(SIZE + 1));
+ q.put(new PDelay(SIZE+1));
}});
t.start();
@@ -792,7 +788,7 @@
ArrayList l = new ArrayList();
q.drainTo(l, i);
int k = (i < SIZE) ? i : SIZE;
- assertEquals(SIZE - k, q.size());
+ assertEquals(SIZE-k, q.size());
assertEquals(k, l.size());
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/DoubleAccumulatorTest.java b/jsr166-tests/src/test/java/jsr166/DoubleAccumulatorTest.java
deleted file mode 100644
index e061f9a..0000000
--- a/jsr166-tests/src/test/java/jsr166/DoubleAccumulatorTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Phaser;
-import java.util.concurrent.atomic.DoubleAccumulator;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class DoubleAccumulatorTest extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(DoubleAccumulatorTest.class);
- // }
-
- /**
- * default constructed initializes to zero
- */
- public void testConstructor() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals(0.0, ai.get());
- }
-
- /**
- * accumulate accumulates given value to current, and get returns current value
- */
- public void testAccumulateAndGet() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- ai.accumulate(2.0);
- assertEquals(2.0, ai.get());
- ai.accumulate(-4.0);
- assertEquals(2.0, ai.get());
- ai.accumulate(4.0);
- assertEquals(4.0, ai.get());
- }
-
- /**
- * reset() causes subsequent get() to return zero
- */
- public void testReset() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- ai.accumulate(2.0);
- assertEquals(2.0, ai.get());
- ai.reset();
- assertEquals(0.0, ai.get());
- }
-
- /**
- * getThenReset() returns current value; subsequent get() returns zero
- */
- public void testGetThenReset() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- ai.accumulate(2.0);
- assertEquals(2.0, ai.get());
- assertEquals(2.0, ai.getThenReset());
- assertEquals(0.0, ai.get());
- }
-
- /**
- * toString returns current value.
- */
- public void testToString() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals("0.0", ai.toString());
- ai.accumulate(1.0);
- assertEquals(Double.toString(1.0), ai.toString());
- }
-
- /**
- * intValue returns current value.
- */
- public void testIntValue() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals(0, ai.intValue());
- ai.accumulate(1.0);
- assertEquals(1, ai.intValue());
- }
-
- /**
- * longValue returns current value.
- */
- public void testLongValue() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals(0, ai.longValue());
- ai.accumulate(1.0);
- assertEquals(1, ai.longValue());
- }
-
- /**
- * floatValue returns current value.
- */
- public void testFloatValue() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals(0.0f, ai.floatValue());
- ai.accumulate(1.0);
- assertEquals(1.0f, ai.floatValue());
- }
-
- /**
- * doubleValue returns current value.
- */
- public void testDoubleValue() {
- DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0);
- assertEquals(0.0, ai.doubleValue());
- ai.accumulate(1.0);
- assertEquals(1.0, ai.doubleValue());
- }
-
- /**
- * accumulates by multiple threads produce correct result
- */
- public void testAccumulateAndGetMT() {
- final int incs = 1000000;
- final int nthreads = 4;
- final ExecutorService pool = Executors.newCachedThreadPool();
- DoubleAccumulator a = new DoubleAccumulator(Double::max, 0.0);
- Phaser phaser = new Phaser(nthreads + 1);
- for (int i = 0; i < nthreads; ++i)
- pool.execute(new AccTask(a, phaser, incs));
- phaser.arriveAndAwaitAdvance();
- phaser.arriveAndAwaitAdvance();
- double expected = incs - 1;
- double result = a.get();
- assertEquals(expected, result);
- pool.shutdown();
- }
-
- static final class AccTask implements Runnable {
- final DoubleAccumulator acc;
- final Phaser phaser;
- final int incs;
- volatile double result;
- AccTask(DoubleAccumulator acc, Phaser phaser, int incs) {
- this.acc = acc;
- this.phaser = phaser;
- this.incs = incs;
- }
-
- public void run() {
- phaser.arriveAndAwaitAdvance();
- DoubleAccumulator a = acc;
- for (int i = 0; i < incs; ++i)
- a.accumulate(i);
- result = a.get();
- phaser.arrive();
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/DoubleAdderTest.java b/jsr166-tests/src/test/java/jsr166/DoubleAdderTest.java
deleted file mode 100644
index d02e2a1..0000000
--- a/jsr166-tests/src/test/java/jsr166/DoubleAdderTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.DoubleAdder;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class DoubleAdderTest extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(DoubleAdderTest.class);
- // }
-
- /**
- * default constructed initializes to zero
- */
- public void testConstructor() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(0.0, ai.sum());
- }
-
- /**
- * add adds given value to current, and sum returns current value
- */
- public void testAddAndSum() {
- DoubleAdder ai = new DoubleAdder();
- ai.add(2.0);
- assertEquals(2.0, ai.sum());
- ai.add(-4.0);
- assertEquals(-2.0, ai.sum());
- }
-
- /**
- * reset() causes subsequent sum() to return zero
- */
- public void testReset() {
- DoubleAdder ai = new DoubleAdder();
- ai.add(2.0);
- assertEquals(2.0, ai.sum());
- ai.reset();
- assertEquals(0.0, ai.sum());
- }
-
- /**
- * sumThenReset() returns sum; subsequent sum() returns zero
- */
- public void testSumThenReset() {
- DoubleAdder ai = new DoubleAdder();
- ai.add(2.0);
- assertEquals(2.0, ai.sum());
- assertEquals(2.0, ai.sumThenReset());
- assertEquals(0.0, ai.sum());
- }
-
- /**
- * a deserialized serialized adder holds same value
- */
- public void testSerialization() throws Exception {
- DoubleAdder x = new DoubleAdder();
- DoubleAdder y = serialClone(x);
- assertNotSame(x, y);
- x.add(-22.0);
- DoubleAdder z = serialClone(x);
- assertEquals(-22.0, x.sum());
- assertEquals(0.0, y.sum());
- assertEquals(-22.0, z.sum());
- }
-
- /**
- * toString returns current value.
- */
- public void testToString() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(Double.toString(0.0), ai.toString());
- ai.add(1.0);
- assertEquals(Double.toString(1.0), ai.toString());
- }
-
- /**
- * intValue returns current value.
- */
- public void testIntValue() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(0, ai.intValue());
- ai.add(1.0);
- assertEquals(1, ai.intValue());
- }
-
- /**
- * longValue returns current value.
- */
- public void testLongValue() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(0, ai.longValue());
- ai.add(1.0);
- assertEquals(1, ai.longValue());
- }
-
- /**
- * floatValue returns current value.
- */
- public void testFloatValue() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(0.0f, ai.floatValue());
- ai.add(1.0);
- assertEquals(1.0f, ai.floatValue());
- }
-
- /**
- * doubleValue returns current value.
- */
- public void testDoubleValue() {
- DoubleAdder ai = new DoubleAdder();
- assertEquals(0.0, ai.doubleValue());
- ai.add(1.0);
- assertEquals(1.0, ai.doubleValue());
- }
-
- /**
- * adds by multiple threads produce correct sum
- */
- public void testAddAndSumMT() throws Throwable {
- final int incs = 1000000;
- final int nthreads = 4;
- final ExecutorService pool = Executors.newCachedThreadPool();
- DoubleAdder a = new DoubleAdder();
- CyclicBarrier barrier = new CyclicBarrier(nthreads + 1);
- for (int i = 0; i < nthreads; ++i)
- pool.execute(new AdderTask(a, barrier, incs));
- barrier.await();
- barrier.await();
- double total = (long)nthreads * incs;
- double sum = a.sum();
- assertEquals(sum, total);
- pool.shutdown();
- }
-
- static final class AdderTask implements Runnable {
- final DoubleAdder adder;
- final CyclicBarrier barrier;
- final int incs;
- volatile double result;
- AdderTask(DoubleAdder adder, CyclicBarrier barrier, int incs) {
- this.adder = adder;
- this.barrier = barrier;
- this.incs = incs;
- }
-
- public void run() {
- try {
- barrier.await();
- DoubleAdder a = adder;
- for (int i = 0; i < incs; ++i)
- a.add(1.0);
- result = a.sum();
- barrier.await();
- } catch (Throwable t) { throw new Error(t); }
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/EntryTest.java b/jsr166-tests/src/test/java/jsr166/EntryTest.java
index 72740e3..d141a84 100644
--- a/jsr166-tests/src/test/java/jsr166/EntryTest.java
+++ b/jsr166-tests/src/test/java/jsr166/EntryTest.java
@@ -20,7 +20,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(EntryTest.class);
+ // return new TestSuite(...);
// }
static final String k1 = "1";
diff --git a/jsr166-tests/src/test/java/jsr166/ExchangerTest.java b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
index b111980..172fccd 100644
--- a/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
@@ -26,7 +26,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ExchangerTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
index 0f58e78..e988cc6 100644
--- a/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
@@ -33,7 +33,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ExecutorCompletionServiceTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -61,14 +61,15 @@
* Submitting a null callable throws NPE
*/
public void testSubmitNPE() {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
Callable c = null;
- try {
- ecs.submit(c);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ecs.submit(c);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -76,14 +77,15 @@
* Submitting a null runnable throws NPE
*/
public void testSubmitNPE2() {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
Runnable r = null;
- try {
- ecs.submit(r, Boolean.TRUE);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ecs.submit(r, Boolean.TRUE);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -91,13 +93,15 @@
* A taken submitted task is completed
*/
public void testTake() throws InterruptedException {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
Callable c = new StringTask();
ecs.submit(c);
Future f = ecs.take();
assertTrue(f.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -105,13 +109,15 @@
* Take returns the same future object returned by submit
*/
public void testTake2() throws InterruptedException {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
Callable c = new StringTask();
Future f1 = ecs.submit(c);
Future f2 = ecs.take();
assertSame(f1, f2);
+ } finally {
+ joinPool(e);
}
}
@@ -119,9 +125,9 @@
* If poll returns non-null, the returned task is completed
*/
public void testPoll1() throws Exception {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
assertNull(ecs.poll());
Callable c = new StringTask();
ecs.submit(c);
@@ -135,6 +141,8 @@
}
assertTrue(f.isDone());
assertSame(TEST_STRING, f.get());
+ } finally {
+ joinPool(e);
}
}
@@ -142,15 +150,17 @@
* If timed poll returns non-null, the returned task is completed
*/
public void testPoll2() throws InterruptedException {
- final ExecutorService e = Executors.newCachedThreadPool();
- final ExecutorCompletionService ecs = new ExecutorCompletionService(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
assertNull(ecs.poll());
Callable c = new StringTask();
ecs.submit(c);
Future f = ecs.poll(SHORT_DELAY_MS, MILLISECONDS);
if (f != null)
assertTrue(f.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -164,16 +174,15 @@
MyCallableFuture(Callable<V> c) { super(c); }
protected void done() { done.set(true); }
}
- final ExecutorService e =
- new ThreadPoolExecutor(1, 1,
- 30L, TimeUnit.SECONDS,
- new ArrayBlockingQueue<Runnable>(1)) {
- protected <T> RunnableFuture<T> newTaskFor(Callable<T> c) {
- return new MyCallableFuture<T>(c);
- }};
+ ExecutorService e = new ThreadPoolExecutor(
+ 1, 1, 30L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(1)) {
+ protected <T> RunnableFuture<T> newTaskFor(Callable<T> c) {
+ return new MyCallableFuture<T>(c);
+ }};
ExecutorCompletionService<String> ecs =
new ExecutorCompletionService<String>(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
assertNull(ecs.poll());
Callable<String> c = new StringTask();
Future f1 = ecs.submit(c);
@@ -182,6 +191,8 @@
Future f2 = ecs.take();
assertSame("submit and take must return same objects", f1, f2);
assertTrue("completed task must have set done", done.get());
+ } finally {
+ joinPool(e);
}
}
@@ -195,16 +206,15 @@
MyRunnableFuture(Runnable t, V r) { super(t, r); }
protected void done() { done.set(true); }
}
- final ExecutorService e =
- new ThreadPoolExecutor(1, 1,
- 30L, TimeUnit.SECONDS,
- new ArrayBlockingQueue<Runnable>(1)) {
- protected <T> RunnableFuture<T> newTaskFor(Runnable t, T r) {
- return new MyRunnableFuture<T>(t, r);
- }};
- final ExecutorCompletionService<String> ecs =
+ ExecutorService e = new ThreadPoolExecutor(
+ 1, 1, 30L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(1)) {
+ protected <T> RunnableFuture<T> newTaskFor(Runnable t, T r) {
+ return new MyRunnableFuture<T>(t, r);
+ }};
+ ExecutorCompletionService<String> ecs =
new ExecutorCompletionService<String>(e);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
assertNull(ecs.poll());
Runnable r = new NoOpRunnable();
Future f1 = ecs.submit(r, null);
@@ -213,6 +223,8 @@
Future f2 = ecs.take();
assertSame("submit and take must return same objects", f1, f2);
assertTrue("completed task must have set done", done.get());
+ } finally {
+ joinPool(e);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
index d70ae6e..ae475f1 100644
--- a/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
@@ -36,31 +36,29 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ExecutorsTest.class);
+ // return new TestSuite(...);
// }
/**
* A newCachedThreadPool can execute runnables
*/
public void testNewCachedThreadPool1() {
- final ExecutorService e = Executors.newCachedThreadPool();
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newCachedThreadPool();
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
* A newCachedThreadPool with given ThreadFactory can execute runnables
*/
public void testNewCachedThreadPool2() {
- final ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
@@ -77,24 +75,22 @@
* A new SingleThreadExecutor can execute runnables
*/
public void testNewSingleThreadExecutor1() {
- final ExecutorService e = Executors.newSingleThreadExecutor();
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newSingleThreadExecutor();
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
* A new SingleThreadExecutor with given ThreadFactory can execute runnables
*/
public void testNewSingleThreadExecutor2() {
- final ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
@@ -111,12 +107,13 @@
* A new SingleThreadExecutor cannot be casted to concrete implementation
*/
public void testCastNewSingleThreadExecutor() {
- final ExecutorService e = Executors.newSingleThreadExecutor();
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- ThreadPoolExecutor tpe = (ThreadPoolExecutor)e;
- shouldThrow();
- } catch (ClassCastException success) {}
+ ExecutorService e = Executors.newSingleThreadExecutor();
+ try {
+ ThreadPoolExecutor tpe = (ThreadPoolExecutor)e;
+ shouldThrow();
+ } catch (ClassCastException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -124,24 +121,22 @@
* A new newFixedThreadPool can execute runnables
*/
public void testNewFixedThreadPool1() {
- final ExecutorService e = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newFixedThreadPool(2);
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
* A new newFixedThreadPool with given ThreadFactory can execute runnables
*/
public void testNewFixedThreadPool2() {
- final ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
@@ -168,12 +163,11 @@
* An unconfigurable newFixedThreadPool can execute runnables
*/
public void testUnconfigurableExecutorService() {
- final ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2));
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- e.execute(new NoOpRunnable());
- }
+ ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2));
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
}
/**
@@ -200,8 +194,8 @@
* a newSingleThreadScheduledExecutor successfully runs delayed task
*/
public void testNewSingleThreadScheduledExecutor() throws Exception {
- final ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor();
- try (PoolCleaner cleaner = cleaner(p)) {
+ ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor();
+ try {
final CountDownLatch proceed = new CountDownLatch(1);
final Runnable task = new CheckedRunnable() {
public void realRun() {
@@ -217,6 +211,8 @@
assertTrue(f.isDone());
assertFalse(f.isCancelled());
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
}
}
@@ -224,8 +220,8 @@
* a newScheduledThreadPool successfully runs delayed task
*/
public void testNewScheduledThreadPool() throws Exception {
- final ScheduledExecutorService p = Executors.newScheduledThreadPool(2);
- try (PoolCleaner cleaner = cleaner(p)) {
+ ScheduledExecutorService p = Executors.newScheduledThreadPool(2);
+ try {
final CountDownLatch proceed = new CountDownLatch(1);
final Runnable task = new CheckedRunnable() {
public void realRun() {
@@ -241,6 +237,8 @@
assertTrue(f.isDone());
assertFalse(f.isCancelled());
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
}
}
@@ -248,10 +246,10 @@
* an unconfigurable newScheduledThreadPool successfully runs delayed task
*/
public void testUnconfigurableScheduledExecutorService() throws Exception {
- final ScheduledExecutorService p =
+ ScheduledExecutorService p =
Executors.unconfigurableScheduledExecutorService
(Executors.newScheduledThreadPool(2));
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
final CountDownLatch proceed = new CountDownLatch(1);
final Runnable task = new CheckedRunnable() {
public void realRun() {
@@ -267,6 +265,8 @@
assertTrue(f.isDone());
assertFalse(f.isCancelled());
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
}
}
@@ -327,10 +327,16 @@
done.countDown();
}};
ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(r);
- await(done);
+
+ e.execute(r);
+ await(done);
+
+ try {
+ e.shutdown();
+ } catch (SecurityException ok) {
}
+
+ joinPool(e);
}
/**
@@ -360,14 +366,14 @@
String name = current.getName();
assertTrue(name.endsWith("thread-1"));
assertSame(thisccl, current.getContextClassLoader());
- //assertEquals(thisacc, AccessController.getContext());
+ // assertEquals(thisacc, AccessController.getContext());
done.countDown();
}};
ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
- e.execute(r);
- await(done);
- }
+ e.execute(r);
+ await(done);
+ e.shutdown();
+ joinPool(e);
}};
runWithPermissions(r,
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinPool8Test.java b/jsr166-tests/src/test/java/jsr166/ForkJoinPool8Test.java
deleted file mode 100644
index f9f9239..0000000
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinPool8Test.java
+++ /dev/null
@@ -1,1592 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import java.util.HashSet;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CountedCompleter;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.RecursiveAction;
-import java.util.concurrent.TimeoutException;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class ForkJoinPool8Test extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(ForkJoinPool8Test.class);
- // }
-
- /**
- * Common pool exists and has expected parallelism.
- */
- public void testCommonPoolParallelism() {
- assertEquals(ForkJoinPool.getCommonPoolParallelism(),
- ForkJoinPool.commonPool().getParallelism());
- }
-
- /**
- * Common pool cannot be shut down
- */
- public void testCommonPoolShutDown() {
- assertFalse(ForkJoinPool.commonPool().isShutdown());
- assertFalse(ForkJoinPool.commonPool().isTerminating());
- assertFalse(ForkJoinPool.commonPool().isTerminated());
- ForkJoinPool.commonPool().shutdown();
- assertFalse(ForkJoinPool.commonPool().isShutdown());
- assertFalse(ForkJoinPool.commonPool().isTerminating());
- assertFalse(ForkJoinPool.commonPool().isTerminated());
- ForkJoinPool.commonPool().shutdownNow();
- assertFalse(ForkJoinPool.commonPool().isShutdown());
- assertFalse(ForkJoinPool.commonPool().isTerminating());
- assertFalse(ForkJoinPool.commonPool().isTerminated());
- }
-
- /*
- * All of the following test methods are adaptations of those for
- * RecursiveAction and CountedCompleter, but with all actions
- * executed in the common pool, generally implicitly via
- * checkInvoke.
- */
-
- private void checkInvoke(ForkJoinTask a) {
- checkNotDone(a);
- assertNull(a.invoke());
- checkCompletedNormally(a);
- }
-
- void checkNotDone(ForkJoinTask a) {
- assertFalse(a.isDone());
- assertFalse(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertFalse(a.isCancelled());
- assertNull(a.getException());
- assertNull(a.getRawResult());
-
- if (! ForkJoinTask.inForkJoinPool()) {
- Thread.currentThread().interrupt();
- try {
- a.get();
- shouldThrow();
- } catch (InterruptedException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- Thread.currentThread().interrupt();
- try {
- a.get(5L, SECONDS);
- shouldThrow();
- } catch (InterruptedException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- try {
- a.get(0L, SECONDS);
- shouldThrow();
- } catch (TimeoutException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- void checkCompletedNormally(ForkJoinTask a) {
- assertTrue(a.isDone());
- assertFalse(a.isCancelled());
- assertTrue(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertNull(a.getException());
- assertNull(a.getRawResult());
- assertNull(a.join());
- assertFalse(a.cancel(false));
- assertFalse(a.cancel(true));
- try {
- assertNull(a.get());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- try {
- assertNull(a.get(5L, SECONDS));
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- void checkCancelled(ForkJoinTask a) {
- assertTrue(a.isDone());
- assertTrue(a.isCancelled());
- assertFalse(a.isCompletedNormally());
- assertTrue(a.isCompletedAbnormally());
- assertTrue(a.getException() instanceof CancellationException);
- assertNull(a.getRawResult());
-
- try {
- a.join();
- shouldThrow();
- } catch (CancellationException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- a.get();
- shouldThrow();
- } catch (CancellationException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- a.get(5L, SECONDS);
- shouldThrow();
- } catch (CancellationException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- void checkCompletedAbnormally(ForkJoinTask a, Throwable t) {
- assertTrue(a.isDone());
- assertFalse(a.isCancelled());
- assertFalse(a.isCompletedNormally());
- assertTrue(a.isCompletedAbnormally());
- assertSame(t.getClass(), a.getException().getClass());
- assertNull(a.getRawResult());
- assertFalse(a.cancel(false));
- assertFalse(a.cancel(true));
-
- try {
- a.join();
- shouldThrow();
- } catch (Throwable expected) {
- assertSame(expected.getClass(), t.getClass());
- }
-
- try {
- a.get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(t.getClass(), success.getCause().getClass());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- a.get(5L, SECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(t.getClass(), success.getCause().getClass());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- public static final class FJException extends RuntimeException {
- public FJException() { super(); }
- public FJException(Throwable cause) { super(cause); }
- }
-
- // A simple recursive action for testing
- final class FibAction extends CheckedRecursiveAction {
- final int number;
- int result;
- FibAction(int n) { number = n; }
- protected void realCompute() {
- int n = number;
- if (n <= 1)
- result = n;
- else {
- FibAction f1 = new FibAction(n - 1);
- FibAction f2 = new FibAction(n - 2);
- invokeAll(f1, f2);
- result = f1.result + f2.result;
- }
- }
- }
-
- // A recursive action failing in base case
- static final class FailingFibAction extends RecursiveAction {
- final int number;
- int result;
- FailingFibAction(int n) { number = n; }
- public void compute() {
- int n = number;
- if (n <= 1)
- throw new FJException();
- else {
- FailingFibAction f1 = new FailingFibAction(n - 1);
- FailingFibAction f2 = new FailingFibAction(n - 2);
- invokeAll(f1, f2);
- result = f1.result + f2.result;
- }
- }
- }
-
- /**
- * invoke returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks. getRawResult of a RecursiveAction returns null;
- */
- public void testInvoke() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertNull(f.invoke());
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyInvoke task returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks
- */
- public void testQuietlyInvoke() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- f.quietlyInvoke();
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task returns when task completes
- */
- public void testForkJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- assertNull(f.join());
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * join/quietlyJoin of a forked task succeeds in the presence of interrupts
- */
- public void testJoinIgnoresInterrupts() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- final Thread myself = Thread.currentThread();
-
- // test join()
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- assertNull(f.join());
- Thread.interrupted();
- assertEquals(21, f.result);
- checkCompletedNormally(f);
-
- f = new FibAction(8);
- f.cancel(true);
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- try {
- f.join();
- shouldThrow();
- } catch (CancellationException success) {
- Thread.interrupted();
- checkCancelled(f);
- }
-
- f = new FibAction(8);
- f.completeExceptionally(new FJException());
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- try {
- f.join();
- shouldThrow();
- } catch (FJException success) {
- Thread.interrupted();
- checkCompletedAbnormally(f, success);
- }
-
- // test quietlyJoin()
- f = new FibAction(8);
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- f.quietlyJoin();
- Thread.interrupted();
- assertEquals(21, f.result);
- checkCompletedNormally(f);
-
- f = new FibAction(8);
- f.cancel(true);
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- f.quietlyJoin();
- Thread.interrupted();
- checkCancelled(f);
-
- f = new FibAction(8);
- f.completeExceptionally(new FJException());
- assertSame(f, f.fork());
- myself.interrupt();
- assertTrue(myself.isInterrupted());
- f.quietlyJoin();
- Thread.interrupted();
- checkCompletedAbnormally(f, f.getException());
- }};
- checkInvoke(a);
- a.reinitialize();
- checkInvoke(a);
- }
-
- /**
- * get of a forked task returns when task completes
- */
- public void testForkGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- assertNull(f.get());
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task returns when task completes
- */
- public void testForkTimedGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- assertNull(f.get(5L, SECONDS));
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get with null time unit throws NPE
- */
- public void testForkTimedGetNPE() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- try {
- f.get(5L, null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes
- */
- public void testForkQuietlyJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task throws exception when task completes abnormally
- */
- public void testAbnormalInvoke() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyInvoke task returns when task completes abnormally
- */
- public void testAbnormalQuietlyInvoke() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- f.quietlyInvoke();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- assertSame(f, f.fork());
- try {
- f.join();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingFibAction f = new FailingFibAction(8);
- assertSame(f, f.fork());
- try {
- f.get();
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkTimedGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingFibAction f = new FailingFibAction(8);
- assertSame(f, f.fork());
- try {
- f.get(5L, SECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes abnormally
- */
- public void testAbnormalForkQuietlyJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task throws exception when task cancelled
- */
- public void testCancelledInvoke() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertTrue(f.cancel(true));
- try {
- f.invoke();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task throws exception when task cancelled
- */
- public void testCancelledForkJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.join();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * get of a forked task throws exception when task cancelled
- */
- public void testCancelledForkGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FibAction f = new FibAction(8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.get();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task throws exception when task cancelled
- */
- public void testCancelledForkTimedGet() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FibAction f = new FibAction(8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.get(5L, SECONDS);
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task cancelled
- */
- public void testCancelledForkQuietlyJoin() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- f.quietlyJoin();
- checkCancelled(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * inForkJoinPool of non-FJ task returns false
- */
- public void testInForkJoinPool2() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertFalse(inForkJoinPool());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * A reinitialized normally completed task may be re-invoked
- */
- public void testReinitialize() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- checkNotDone(f);
-
- for (int i = 0; i < 3; i++) {
- assertNull(f.invoke());
- assertEquals(21, f.result);
- checkCompletedNormally(f);
- f.reinitialize();
- checkNotDone(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * A reinitialized abnormally completed task may be re-invoked
- */
- public void testReinitializeAbnormal() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- checkNotDone(f);
-
- for (int i = 0; i < 3; i++) {
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- f.reinitialize();
- checkNotDone(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task throws exception after invoking completeExceptionally
- */
- public void testCompleteExceptionally() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- f.completeExceptionally(new FJException());
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task suppresses execution invoking complete
- */
- public void testComplete() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- f.complete(null);
- assertNull(f.invoke());
- assertEquals(0, f.result);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(t1, t2) invokes all task arguments
- */
- public void testInvokeAll2() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FibAction g = new FibAction(9);
- invokeAll(f, g);
- checkCompletedNormally(f);
- assertEquals(21, f.result);
- checkCompletedNormally(g);
- assertEquals(34, g.result);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument invokes task
- */
- public void testInvokeAll1() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- invokeAll(f);
- checkCompletedNormally(f);
- assertEquals(21, f.result);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument invokes tasks
- */
- public void testInvokeAll3() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FibAction g = new FibAction(9);
- FibAction h = new FibAction(7);
- invokeAll(f, g, h);
- assertTrue(f.isDone());
- assertTrue(g.isDone());
- assertTrue(h.isDone());
- checkCompletedNormally(f);
- assertEquals(21, f.result);
- checkCompletedNormally(g);
- assertEquals(34, g.result);
- checkCompletedNormally(g);
- assertEquals(13, h.result);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(collection) invokes all tasks in the collection
- */
- public void testInvokeAllCollection() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FibAction g = new FibAction(9);
- FibAction h = new FibAction(7);
- HashSet set = new HashSet();
- set.add(f);
- set.add(g);
- set.add(h);
- invokeAll(set);
- assertTrue(f.isDone());
- assertTrue(g.isDone());
- assertTrue(h.isDone());
- checkCompletedNormally(f);
- assertEquals(21, f.result);
- checkCompletedNormally(g);
- assertEquals(34, g.result);
- checkCompletedNormally(g);
- assertEquals(13, h.result);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with any null task throws NPE
- */
- public void testInvokeAllNPE() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FibAction g = new FibAction(9);
- FibAction h = null;
- try {
- invokeAll(f, g, h);
- shouldThrow();
- } catch (NullPointerException success) {}
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(t1, t2) throw exception if any task does
- */
- public void testAbnormalInvokeAll2() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FailingFibAction g = new FailingFibAction(9);
- try {
- invokeAll(f, g);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument throws exception if task does
- */
- public void testAbnormalInvokeAll1() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction g = new FailingFibAction(9);
- try {
- invokeAll(g);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument throws exception if any task does
- */
- public void testAbnormalInvokeAll3() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- FailingFibAction g = new FailingFibAction(9);
- FibAction h = new FibAction(7);
- try {
- invokeAll(f, g, h);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(collection) throws exception if any task does
- */
- public void testAbnormalInvokeAllCollection() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingFibAction f = new FailingFibAction(8);
- FibAction g = new FibAction(9);
- FibAction h = new FibAction(7);
- HashSet set = new HashSet();
- set.add(f);
- set.add(g);
- set.add(h);
- try {
- invokeAll(set);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- // CountedCompleter versions
-
- abstract static class CCF extends CountedCompleter {
- int number;
- int rnumber;
-
- public CCF(CountedCompleter parent, int n) {
- super(parent, 1);
- this.number = n;
- }
-
- public final void compute() {
- CountedCompleter p;
- CCF f = this;
- int n = number;
- while (n >= 2) {
- new RCCF(f, n - 2).fork();
- f = new LCCF(f, --n);
- }
- f.number = n;
- f.onCompletion(f);
- if ((p = f.getCompleter()) != null)
- p.tryComplete();
- else
- f.quietlyComplete();
- }
- }
-
- static final class LCCF extends CCF {
- public LCCF(CountedCompleter parent, int n) {
- super(parent, n);
- }
- public final void onCompletion(CountedCompleter caller) {
- CCF p = (CCF)getCompleter();
- int n = number + rnumber;
- if (p != null)
- p.number = n;
- else
- number = n;
- }
- }
- static final class RCCF extends CCF {
- public RCCF(CountedCompleter parent, int n) {
- super(parent, n);
- }
- public final void onCompletion(CountedCompleter caller) {
- CCF p = (CCF)getCompleter();
- int n = number + rnumber;
- if (p != null)
- p.rnumber = n;
- else
- number = n;
- }
- }
-
- // Version of CCF with forced failure in left completions
- abstract static class FailingCCF extends CountedCompleter {
- int number;
- int rnumber;
-
- public FailingCCF(CountedCompleter parent, int n) {
- super(parent, 1);
- this.number = n;
- }
-
- public final void compute() {
- CountedCompleter p;
- FailingCCF f = this;
- int n = number;
- while (n >= 2) {
- new RFCCF(f, n - 2).fork();
- f = new LFCCF(f, --n);
- }
- f.number = n;
- f.onCompletion(f);
- if ((p = f.getCompleter()) != null)
- p.tryComplete();
- else
- f.quietlyComplete();
- }
- }
-
- static final class LFCCF extends FailingCCF {
- public LFCCF(CountedCompleter parent, int n) {
- super(parent, n);
- }
- public final void onCompletion(CountedCompleter caller) {
- FailingCCF p = (FailingCCF)getCompleter();
- int n = number + rnumber;
- if (p != null)
- p.number = n;
- else
- number = n;
- }
- }
- static final class RFCCF extends FailingCCF {
- public RFCCF(CountedCompleter parent, int n) {
- super(parent, n);
- }
- public final void onCompletion(CountedCompleter caller) {
- completeExceptionally(new FJException());
- }
- }
-
- /**
- * invoke returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks; getRawResult returns null.
- */
- public void testInvokeCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertNull(f.invoke());
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyInvoke task returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks
- */
- public void testQuietlyInvokeCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- f.quietlyInvoke();
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task returns when task completes
- */
- public void testForkJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertSame(f, f.fork());
- assertNull(f.join());
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * get of a forked task returns when task completes
- */
- public void testForkGetCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- CCF f = new LCCF(null, 8);
- assertSame(f, f.fork());
- assertNull(f.get());
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task returns when task completes
- */
- public void testForkTimedGetCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- CCF f = new LCCF(null, 8);
- assertSame(f, f.fork());
- assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get with null time unit throws NPE
- */
- public void testForkTimedGetNPECC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- CCF f = new LCCF(null, 8);
- assertSame(f, f.fork());
- try {
- f.get(5L, null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes
- */
- public void testForkQuietlyJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- assertEquals(21, f.number);
- checkCompletedNormally(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task throws exception when task completes abnormally
- */
- public void testAbnormalInvokeCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF f = new LFCCF(null, 8);
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyInvoke task returns when task completes abnormally
- */
- public void testAbnormalQuietlyInvokeCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF f = new LFCCF(null, 8);
- f.quietlyInvoke();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF f = new LFCCF(null, 8);
- assertSame(f, f.fork());
- try {
- f.join();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkGetCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingCCF f = new LFCCF(null, 8);
- assertSame(f, f.fork());
- try {
- f.get();
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkTimedGetCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingCCF f = new LFCCF(null, 8);
- assertSame(f, f.fork());
- try {
- f.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes abnormally
- */
- public void testAbnormalForkQuietlyJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF f = new LFCCF(null, 8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- checkInvoke(a);
- }
-
- /**
- * invoke task throws exception when task cancelled
- */
- public void testCancelledInvokeCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertTrue(f.cancel(true));
- try {
- f.invoke();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * join of a forked task throws exception when task cancelled
- */
- public void testCancelledForkJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.join();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * get of a forked task throws exception when task cancelled
- */
- public void testCancelledForkGetCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- CCF f = new LCCF(null, 8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.get();
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * timed get of a forked task throws exception when task cancelled
- */
- public void testCancelledForkTimedGetCC() throws Exception {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- CCF f = new LCCF(null, 8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- try {
- f.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (CancellationException success) {
- checkCancelled(f);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task cancelled
- */
- public void testCancelledForkQuietlyJoinCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- assertTrue(f.cancel(true));
- assertSame(f, f.fork());
- f.quietlyJoin();
- checkCancelled(f);
- }};
- checkInvoke(a);
- }
-
- /**
- * getPool of non-FJ task returns null
- */
- public void testGetPool2CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertNull(getPool());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * inForkJoinPool of non-FJ task returns false
- */
- public void testInForkJoinPool2CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertFalse(inForkJoinPool());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * setRawResult(null) succeeds
- */
- public void testSetRawResultCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- setRawResult(null);
- assertNull(getRawResult());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * invoke task throws exception after invoking completeExceptionally
- */
- public void testCompleteExceptionally2CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- f.completeExceptionally(new FJException());
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(t1, t2) invokes all task arguments
- */
- public void testInvokeAll2CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- CCF g = new LCCF(null, 9);
- invokeAll(f, g);
- assertEquals(21, f.number);
- assertEquals(34, g.number);
- checkCompletedNormally(f);
- checkCompletedNormally(g);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument invokes task
- */
- public void testInvokeAll1CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- invokeAll(f);
- checkCompletedNormally(f);
- assertEquals(21, f.number);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument invokes tasks
- */
- public void testInvokeAll3CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- CCF g = new LCCF(null, 9);
- CCF h = new LCCF(null, 7);
- invokeAll(f, g, h);
- assertEquals(21, f.number);
- assertEquals(34, g.number);
- assertEquals(13, h.number);
- checkCompletedNormally(f);
- checkCompletedNormally(g);
- checkCompletedNormally(h);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(collection) invokes all tasks in the collection
- */
- public void testInvokeAllCollectionCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- CCF g = new LCCF(null, 9);
- CCF h = new LCCF(null, 7);
- HashSet set = new HashSet();
- set.add(f);
- set.add(g);
- set.add(h);
- invokeAll(set);
- assertEquals(21, f.number);
- assertEquals(34, g.number);
- assertEquals(13, h.number);
- checkCompletedNormally(f);
- checkCompletedNormally(g);
- checkCompletedNormally(h);
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with any null task throws NPE
- */
- public void testInvokeAllNPECC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- CCF g = new LCCF(null, 9);
- CCF h = null;
- try {
- invokeAll(f, g, h);
- shouldThrow();
- } catch (NullPointerException success) {}
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(t1, t2) throw exception if any task does
- */
- public void testAbnormalInvokeAll2CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- FailingCCF g = new LFCCF(null, 9);
- try {
- invokeAll(f, g);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument throws exception if task does
- */
- public void testAbnormalInvokeAll1CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF g = new LFCCF(null, 9);
- try {
- invokeAll(g);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument throws exception if any task does
- */
- public void testAbnormalInvokeAll3CC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- CCF f = new LCCF(null, 8);
- FailingCCF g = new LFCCF(null, 9);
- CCF h = new LCCF(null, 7);
- try {
- invokeAll(f, g, h);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * invokeAll(collection) throws exception if any task does
- */
- public void testAbnormalInvokeAllCollectionCC() {
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingCCF f = new LFCCF(null, 8);
- CCF g = new LCCF(null, 9);
- CCF h = new LCCF(null, 7);
- HashSet set = new HashSet();
- set.add(f);
- set.add(g);
- set.add(h);
- try {
- invokeAll(set);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- checkInvoke(a);
- }
-
- /**
- * awaitQuiescence by a worker is equivalent in effect to
- * ForkJoinTask.helpQuiesce()
- */
- public void testAwaitQuiescence1() throws Exception {
- final ForkJoinPool p = new ForkJoinPool();
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- assertTrue(p.isQuiescent());
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- assertSame(p, ForkJoinTask.getPool());
- boolean quiescent = p.awaitQuiescence(LONG_DELAY_MS, MILLISECONDS);
- assertTrue(quiescent);
- assertFalse(p.isQuiescent());
- while (!f.isDone()) {
- assertFalse(p.getAsyncMode());
- assertFalse(p.isShutdown());
- assertFalse(p.isTerminating());
- assertFalse(p.isTerminated());
- Thread.yield();
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- assertFalse(p.isQuiescent());
- assertEquals(0, ForkJoinTask.getQueuedTaskCount());
- assertEquals(21, f.result);
- }};
- p.execute(a);
- while (!a.isDone() || !p.isQuiescent()) {
- assertFalse(p.getAsyncMode());
- assertFalse(p.isShutdown());
- assertFalse(p.isTerminating());
- assertFalse(p.isTerminated());
- Thread.yield();
- }
- assertEquals(0, p.getQueuedTaskCount());
- assertFalse(p.getAsyncMode());
- assertEquals(0, p.getQueuedSubmissionCount());
- assertFalse(p.hasQueuedSubmissions());
- while (p.getActiveThreadCount() != 0
- && millisElapsedSince(startTime) < LONG_DELAY_MS)
- Thread.yield();
- assertFalse(p.isShutdown());
- assertFalse(p.isTerminating());
- assertFalse(p.isTerminated());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- }
- }
-
- /**
- * awaitQuiescence returns when pool isQuiescent() or the indicated
- * timeout elapsed
- */
- public void testAwaitQuiescence2() throws Exception {
- /**
- * """It is possible to disable or limit the use of threads in the
- * common pool by setting the parallelism property to zero. However
- * doing so may cause unjoined tasks to never be executed."""
- */
- if ("0".equals(System.getProperty(
- "java.util.concurrent.ForkJoinPool.common.parallelism")))
- return;
- final ForkJoinPool p = new ForkJoinPool();
- try (PoolCleaner cleaner = cleaner(p)) {
- assertTrue(p.isQuiescent());
- final long startTime = System.nanoTime();
- ForkJoinTask a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FibAction f = new FibAction(8);
- assertSame(f, f.fork());
- while (!f.isDone()
- && millisElapsedSince(startTime) < LONG_DELAY_MS) {
- assertFalse(p.getAsyncMode());
- assertFalse(p.isShutdown());
- assertFalse(p.isTerminating());
- assertFalse(p.isTerminated());
- Thread.yield();
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- assertEquals(0, ForkJoinTask.getQueuedTaskCount());
- assertEquals(21, f.result);
- }};
- p.execute(a);
- assertTrue(p.awaitQuiescence(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isQuiescent());
- assertTrue(a.isDone());
- assertEquals(0, p.getQueuedTaskCount());
- assertFalse(p.getAsyncMode());
- assertEquals(0, p.getQueuedSubmissionCount());
- assertFalse(p.hasQueuedSubmissions());
- while (p.getActiveThreadCount() != 0
- && millisElapsedSince(startTime) < LONG_DELAY_MS)
- Thread.yield();
- assertFalse(p.isShutdown());
- assertFalse(p.isTerminating());
- assertFalse(p.isTerminated());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
index e3bb428..09a3511 100644
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
@@ -40,7 +40,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ForkJoinPoolTest.class);
+ // return new TestSuite(...);
// }
/*
@@ -68,12 +68,10 @@
}
}
- static class MyError extends Error {}
-
// to test handlers
static class FailingFJWSubclass extends ForkJoinWorkerThread {
public FailingFJWSubclass(ForkJoinPool p) { super(p) ; }
- protected void onStart() { super.onStart(); throw new MyError(); }
+ protected void onStart() { super.onStart(); throw new Error(); }
}
static class FailingThreadFactory
@@ -168,7 +166,7 @@
*/
public void testDefaultInitialState() {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory,
p.getFactory());
assertFalse(p.getAsyncMode());
@@ -180,6 +178,8 @@
assertFalse(p.isShutdown());
assertFalse(p.isTerminating());
assertFalse(p.isTerminated());
+ } finally {
+ joinPool(p);
}
}
@@ -208,8 +208,10 @@
*/
public void testGetParallelism() {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
assertEquals(1, p.getParallelism());
+ } finally {
+ joinPool(p);
}
}
@@ -217,26 +219,14 @@
* getPoolSize returns number of started workers.
*/
public void testGetPoolSize() {
- final CountDownLatch taskStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
- final ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
assertEquals(0, p.getActiveThreadCount());
- final Runnable task = new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- taskStarted.countDown();
- assertEquals(1, p.getPoolSize());
- assertEquals(1, p.getActiveThreadCount());
- done.await();
- }};
- Future<?> future = p.submit(task);
- await(taskStarted);
+ Future<String> future = p.submit(new StringTask());
assertEquals(1, p.getPoolSize());
- assertEquals(1, p.getActiveThreadCount());
- done.countDown();
+ } finally {
+ joinPool(p);
}
- assertEquals(0, p.getPoolSize());
- assertEquals(0, p.getActiveThreadCount());
}
/**
@@ -244,28 +234,26 @@
*/
public void testAwaitTermination_timesOut() throws InterruptedException {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.isTerminated());
- assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
- assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
- assertFalse(p.awaitTermination(-1L, NANOSECONDS));
- assertFalse(p.awaitTermination(-1L, MILLISECONDS));
- assertFalse(p.awaitTermination(0L, NANOSECONDS));
- assertFalse(p.awaitTermination(0L, MILLISECONDS));
- long timeoutNanos = 999999L;
- long startTime = System.nanoTime();
- assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
- assertTrue(System.nanoTime() - startTime >= timeoutNanos);
- assertFalse(p.isTerminated());
- startTime = System.nanoTime();
- long timeoutMillis = timeoutMillis();
- assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- assertFalse(p.isTerminated());
- p.shutdown();
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- }
+ assertFalse(p.isTerminated());
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
+ assertFalse(p.awaitTermination(-1L, NANOSECONDS));
+ assertFalse(p.awaitTermination(-1L, MILLISECONDS));
+ assertFalse(p.awaitTermination(0L, NANOSECONDS));
+ assertFalse(p.awaitTermination(0L, MILLISECONDS));
+ long timeoutNanos = 999999L;
+ long startTime = System.nanoTime();
+ assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
+ assertTrue(System.nanoTime() - startTime >= timeoutNanos);
+ assertFalse(p.isTerminated());
+ startTime = System.nanoTime();
+ long timeoutMillis = timeoutMillis();
+ assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ assertFalse(p.isTerminated());
+ p.shutdown();
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
}
/**
@@ -276,23 +264,23 @@
*/
public void testSetUncaughtExceptionHandler() throws InterruptedException {
final CountDownLatch uehInvoked = new CountDownLatch(1);
- final Thread.UncaughtExceptionHandler ueh =
+ final Thread.UncaughtExceptionHandler eh =
new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
- threadAssertTrue(e instanceof MyError);
- threadAssertTrue(t instanceof FailingFJWSubclass);
uehInvoked.countDown();
}};
ForkJoinPool p = new ForkJoinPool(1, new FailingThreadFactory(),
- ueh, false);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(ueh, p.getUncaughtExceptionHandler());
+ eh, false);
+ try {
+ assertSame(eh, p.getUncaughtExceptionHandler());
try {
p.execute(new FibTask(8));
- await(uehInvoked);
- } finally {
- p.shutdownNow(); // failure might have prevented processing task
+ assertTrue(uehInvoked.await(MEDIUM_DELAY_MS, MILLISECONDS));
+ } catch (RejectedExecutionException ok) {
}
+ } finally {
+ p.shutdownNow(); // failure might have prevented processing task
+ joinPool(p);
}
}
@@ -304,7 +292,7 @@
*/
public void testIsQuiescent() throws Exception {
ForkJoinPool p = new ForkJoinPool(2);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
assertTrue(p.isQuiescent());
long startTime = System.nanoTime();
FibTask f = new FibTask(20);
@@ -323,18 +311,17 @@
assertTrue(p.isQuiescent());
assertFalse(p.getAsyncMode());
+ assertEquals(0, p.getActiveThreadCount());
assertEquals(0, p.getQueuedTaskCount());
assertEquals(0, p.getQueuedSubmissionCount());
assertFalse(p.hasQueuedSubmissions());
- while (p.getActiveThreadCount() != 0
- && millisElapsedSince(startTime) < LONG_DELAY_MS)
- Thread.yield();
assertFalse(p.isShutdown());
assertFalse(p.isTerminating());
assertFalse(p.isTerminated());
assertTrue(f.isDone());
assertEquals(6765, (int) f.get());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(p);
}
}
@@ -343,9 +330,11 @@
*/
public void testSubmitForkJoinTask() throws Throwable {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
ForkJoinTask<Integer> f = p.submit(new FibTask(8));
assertEquals(21, (int) f.get());
+ } finally {
+ joinPool(p);
}
}
@@ -354,13 +343,15 @@
*/
public void testSubmitAfterShutdown() {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
p.shutdown();
assertTrue(p.isShutdown());
try {
ForkJoinTask<Integer> f = p.submit(new FibTask(8));
shouldThrow();
} catch (RejectedExecutionException success) {}
+ } finally {
+ joinPool(p);
}
}
@@ -386,14 +377,16 @@
public void testPollSubmission() {
final CountDownLatch done = new CountDownLatch(1);
SubFJP p = new SubFJP();
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
ForkJoinTask a = p.submit(awaiter(done));
ForkJoinTask b = p.submit(awaiter(done));
ForkJoinTask c = p.submit(awaiter(done));
ForkJoinTask r = p.pollSubmission();
assertTrue(r == a || r == b || r == c);
assertFalse(r.isDone());
+ } finally {
done.countDown();
+ joinPool(p);
}
}
@@ -403,7 +396,7 @@
public void testDrainTasksTo() {
final CountDownLatch done = new CountDownLatch(1);
SubFJP p = new SubFJP();
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
ForkJoinTask a = p.submit(awaiter(done));
ForkJoinTask b = p.submit(awaiter(done));
ForkJoinTask c = p.submit(awaiter(done));
@@ -414,7 +407,9 @@
assertTrue(r == a || r == b || r == c);
assertFalse(r.isDone());
}
+ } finally {
done.countDown();
+ joinPool(p);
}
}
@@ -425,7 +420,7 @@
*/
public void testExecuteRunnable() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
final AtomicBoolean done = new AtomicBoolean(false);
Future<?> future = e.submit(new CheckedRunnable() {
public void realRun() {
@@ -436,6 +431,8 @@
assertTrue(done.get());
assertTrue(future.isDone());
assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -444,11 +441,13 @@
*/
public void testSubmitCallable() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<String> future = e.submit(new StringTask());
assertSame(TEST_STRING, future.get());
assertTrue(future.isDone());
assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -457,11 +456,13 @@
*/
public void testSubmitRunnable() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<?> future = e.submit(new NoOpRunnable());
assertNull(future.get());
assertTrue(future.isDone());
assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -470,11 +471,13 @@
*/
public void testSubmitRunnable2() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
assertSame(TEST_STRING, future.get());
assertTrue(future.isDone());
assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -487,9 +490,11 @@
Runnable r = new CheckedRunnable() {
public void realRun() throws Exception {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future future = e.submit(callable);
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}};
@@ -506,9 +511,11 @@
Runnable r = new CheckedRunnable() {
public void realRun() throws Exception {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future future = e.submit(callable);
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}};
@@ -525,7 +532,7 @@
Runnable r = new CheckedRunnable() {
public void realRun() throws Exception {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future future = e.submit(callable);
try {
future.get();
@@ -533,6 +540,8 @@
} catch (ExecutionException success) {
assertTrue(success.getCause() instanceof IndexOutOfBoundsException);
}
+ } finally {
+ joinPool(e);
}
}};
@@ -544,11 +553,12 @@
*/
public void testExecuteNullRunnable() {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- Future<?> future = e.submit((Runnable) null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ Future<?> future = e.submit((Runnable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -557,11 +567,12 @@
*/
public void testSubmitNullCallable() {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- Future<String> future = e.submit((Callable) null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ Future<String> future = e.submit((Callable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -571,13 +582,13 @@
public void testInterruptedSubmit() throws InterruptedException {
final CountDownLatch submitted = new CountDownLatch(1);
final CountDownLatch quittingTime = new CountDownLatch(1);
+ final ExecutorService p = new ForkJoinPool(1);
final Callable<Void> awaiter = new CheckedCallable<Void>() {
public Void realCall() throws InterruptedException {
- assertTrue(quittingTime.await(2*LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(quittingTime.await(MEDIUM_DELAY_MS, MILLISECONDS));
return null;
}};
- final ExecutorService p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p, quittingTime)) {
+ try {
Thread t = new Thread(new CheckedInterruptedRunnable() {
public void realRun() throws Exception {
Future<Void> future = p.submit(awaiter);
@@ -585,9 +596,12 @@
future.get();
}});
t.start();
- await(submitted);
+ assertTrue(submitted.await(MEDIUM_DELAY_MS, MILLISECONDS));
t.interrupt();
- awaitTermination(t);
+ t.join();
+ } finally {
+ quittingTime.countDown();
+ joinPool(p);
}
}
@@ -597,15 +611,15 @@
*/
public void testSubmitEE() throws Throwable {
ForkJoinPool p = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.submit(new Callable() {
- public Object call() { throw new ArithmeticException(); }})
- .get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof ArithmeticException);
- }
+ try {
+ p.submit(new Callable() {
+ public Object call() { throw new ArithmeticException(); }})
+ .get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof ArithmeticException);
+ } finally {
+ joinPool(p);
}
}
@@ -614,11 +628,12 @@
*/
public void testInvokeAny1() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -627,11 +642,12 @@
*/
public void testInvokeAny2() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -640,13 +656,14 @@
*/
public void testInvokeAny3() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -656,15 +673,16 @@
public void testInvokeAny4() throws Throwable {
CountDownLatch latch = new CountDownLatch(1);
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -673,15 +691,15 @@
*/
public void testInvokeAny5() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -690,12 +708,14 @@
*/
public void testInvokeAny6() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -704,11 +724,12 @@
*/
public void testInvokeAll1() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -717,10 +738,12 @@
*/
public void testInvokeAll2() throws InterruptedException {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Future<String>> r
= e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -729,14 +752,15 @@
*/
public void testInvokeAll3() throws InterruptedException {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -746,17 +770,17 @@
*/
public void testInvokeAll4() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures = e.invokeAll(l);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -765,7 +789,7 @@
*/
public void testInvokeAll5() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -773,6 +797,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -781,11 +807,12 @@
*/
public void testTimedInvokeAny1() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -794,13 +821,14 @@
*/
public void testTimedInvokeAnyNullTimeUnit() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -809,12 +837,13 @@
*/
public void testTimedInvokeAny2() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -824,15 +853,16 @@
public void testTimedInvokeAny3() throws Throwable {
CountDownLatch latch = new CountDownLatch(1);
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -841,17 +871,15 @@
*/
public void testTimedInvokeAny4() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -860,14 +888,14 @@
*/
public void testTimedInvokeAny5() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -876,11 +904,12 @@
*/
public void testTimedInvokeAll1() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -889,13 +918,14 @@
*/
public void testTimedInvokeAllNullTimeUnit() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -904,11 +934,13 @@
*/
public void testTimedInvokeAll2() throws InterruptedException {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Future<String>> r
= e.invokeAll(new ArrayList<Callable<String>>(),
MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -917,14 +949,15 @@
*/
public void testTimedInvokeAll3() throws InterruptedException {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -933,18 +966,18 @@
*/
public void testTimedInvokeAll4() throws Throwable {
ExecutorService e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures
- = e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures
+ = e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -952,16 +985,18 @@
* timed invokeAll(c) returns results of all completed tasks in c
*/
public void testTimedInvokeAll5() throws Throwable {
- ForkJoinPool e = new ForkJoinPool(1);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures
- = e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ = e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinTask8Test.java b/jsr166-tests/src/test/java/jsr166/ForkJoinTask8Test.java
deleted file mode 100644
index 6c03348..0000000
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinTask8Test.java
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.ForkJoinWorkerThread;
-import java.util.concurrent.RecursiveAction;
-import java.util.concurrent.TimeoutException;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class ForkJoinTask8Test extends JSR166TestCase {
-
- /*
- * Testing notes: This differs from ForkJoinTaskTest mainly by
- * defining a version of BinaryAsyncAction that uses JDK8 task
- * tags for control state, thereby testing getForkJoinTaskTag,
- * setForkJoinTaskTag, and compareAndSetForkJoinTaskTag across
- * various contexts. Most of the test methods using it are
- * otherwise identical, but omitting retest of those dealing with
- * cancellation, which is not represented in this tag scheme.
- */
-
- static final short INITIAL_STATE = -1;
- static final short COMPLETE_STATE = 0;
- static final short EXCEPTION_STATE = 1;
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(ForkJoinTask8Test.class);
- // }
-
- // Runs with "mainPool" use > 1 thread. singletonPool tests use 1
- static final int mainPoolSize =
- Math.max(2, Runtime.getRuntime().availableProcessors());
-
- private static ForkJoinPool mainPool() {
- return new ForkJoinPool(mainPoolSize);
- }
-
- private static ForkJoinPool singletonPool() {
- return new ForkJoinPool(1);
- }
-
- private static ForkJoinPool asyncSingletonPool() {
- return new ForkJoinPool(1,
- ForkJoinPool.defaultForkJoinWorkerThreadFactory,
- null, true);
- }
-
- // Compute fib naively and efficiently
- final int[] fib;
- {
- int[] fib = new int[10];
- fib[0] = 0;
- fib[1] = 1;
- for (int i = 2; i < fib.length; i++)
- fib[i] = fib[i - 1] + fib[i - 2];
- this.fib = fib;
- }
-
- private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
- try (PoolCleaner cleaner = cleaner(pool)) {
- assertFalse(a.isDone());
- assertFalse(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertFalse(a.isCancelled());
- assertNull(a.getException());
- assertNull(a.getRawResult());
-
- assertNull(pool.invoke(a));
-
- assertTrue(a.isDone());
- assertTrue(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertFalse(a.isCancelled());
- assertNull(a.getException());
- assertNull(a.getRawResult());
- }
- }
-
- void checkNotDone(ForkJoinTask a) {
- assertFalse(a.isDone());
- assertFalse(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertFalse(a.isCancelled());
- assertNull(a.getException());
- assertNull(a.getRawResult());
- if (a instanceof BinaryAsyncAction)
- assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() == INITIAL_STATE);
-
- try {
- a.get(0L, SECONDS);
- shouldThrow();
- } catch (TimeoutException success) {
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- <T> void checkCompletedNormally(ForkJoinTask<T> a) {
- checkCompletedNormally(a, null);
- }
-
- <T> void checkCompletedNormally(ForkJoinTask<T> a, T expected) {
- assertTrue(a.isDone());
- assertFalse(a.isCancelled());
- assertTrue(a.isCompletedNormally());
- assertFalse(a.isCompletedAbnormally());
- assertNull(a.getException());
- assertSame(expected, a.getRawResult());
- if (a instanceof BinaryAsyncAction)
- assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() == COMPLETE_STATE);
-
- {
- Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
- assertSame(expected, a.join());
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
- Thread.interrupted();
- }
-
- {
- Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
- a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
- Thread.interrupted();
- }
-
- assertFalse(a.cancel(false));
- assertFalse(a.cancel(true));
- try {
- assertSame(expected, a.get());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- try {
- assertSame(expected, a.get(5L, SECONDS));
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- void checkCompletedAbnormally(ForkJoinTask a, Throwable t) {
- assertTrue(a.isDone());
- assertFalse(a.isCancelled());
- assertFalse(a.isCompletedNormally());
- assertTrue(a.isCompletedAbnormally());
- assertSame(t.getClass(), a.getException().getClass());
- assertNull(a.getRawResult());
- assertFalse(a.cancel(false));
- assertFalse(a.cancel(true));
- if (a instanceof BinaryAsyncAction)
- assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() != INITIAL_STATE);
-
- try {
- Thread.currentThread().interrupt();
- a.join();
- shouldThrow();
- } catch (Throwable expected) {
- assertSame(t.getClass(), expected.getClass());
- }
- Thread.interrupted();
-
- {
- long startTime = System.nanoTime();
- a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
- }
-
- try {
- a.get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(t.getClass(), success.getCause().getClass());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
-
- try {
- a.get(5L, SECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertSame(t.getClass(), success.getCause().getClass());
- } catch (Throwable fail) { threadUnexpectedException(fail); }
- }
-
- public static final class FJException extends RuntimeException {
- FJException() { super(); }
- }
-
- abstract static class BinaryAsyncAction extends ForkJoinTask<Void> {
-
- private volatile BinaryAsyncAction parent;
-
- private volatile BinaryAsyncAction sibling;
-
- protected BinaryAsyncAction() {
- setForkJoinTaskTag(INITIAL_STATE);
- }
-
- public final Void getRawResult() { return null; }
- protected final void setRawResult(Void mustBeNull) { }
-
- public final void linkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) {
- x.parent = y.parent = this;
- x.sibling = y;
- y.sibling = x;
- }
-
- protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
- if (this.getForkJoinTaskTag() != COMPLETE_STATE ||
- x.getForkJoinTaskTag() != COMPLETE_STATE ||
- y.getForkJoinTaskTag() != COMPLETE_STATE) {
- completeThisExceptionally(new FJException());
- }
- }
-
- protected boolean onException() {
- return true;
- }
-
- public void linkAndForkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) {
- linkSubtasks(x, y);
- y.fork();
- x.fork();
- }
-
- private void completeThis() {
- setForkJoinTaskTag(COMPLETE_STATE);
- super.complete(null);
- }
-
- private void completeThisExceptionally(Throwable ex) {
- setForkJoinTaskTag(EXCEPTION_STATE);
- super.completeExceptionally(ex);
- }
-
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (super.cancel(mayInterruptIfRunning)) {
- completeExceptionally(new FJException());
- return true;
- }
- return false;
- }
-
- public final void complete() {
- BinaryAsyncAction a = this;
- for (;;) {
- BinaryAsyncAction s = a.sibling;
- BinaryAsyncAction p = a.parent;
- a.sibling = null;
- a.parent = null;
- a.completeThis();
- if (p == null ||
- p.compareAndSetForkJoinTaskTag(INITIAL_STATE, COMPLETE_STATE))
- break;
- try {
- p.onComplete(a, s);
- } catch (Throwable rex) {
- p.completeExceptionally(rex);
- return;
- }
- a = p;
- }
- }
-
- public final void completeExceptionally(Throwable ex) {
- for (BinaryAsyncAction a = this;;) {
- a.completeThisExceptionally(ex);
- BinaryAsyncAction s = a.sibling;
- if (s != null && !s.isDone())
- s.completeExceptionally(ex);
- if ((a = a.parent) == null)
- break;
- }
- }
-
- public final BinaryAsyncAction getParent() {
- return parent;
- }
-
- public BinaryAsyncAction getSibling() {
- return sibling;
- }
-
- public void reinitialize() {
- parent = sibling = null;
- super.reinitialize();
- }
-
- }
-
- final class AsyncFib extends BinaryAsyncAction {
- int number;
- int expectedResult;
- public AsyncFib(int number) {
- this.number = number;
- this.expectedResult = fib[number];
- }
-
- public final boolean exec() {
- try {
- AsyncFib f = this;
- int n = f.number;
- while (n > 1) {
- AsyncFib p = f;
- AsyncFib r = new AsyncFib(n - 2);
- f = new AsyncFib(--n);
- p.linkSubtasks(r, f);
- r.fork();
- }
- f.complete();
- }
- catch (Throwable ex) {
- compareAndSetForkJoinTaskTag(INITIAL_STATE, EXCEPTION_STATE);
- }
- if (getForkJoinTaskTag() == EXCEPTION_STATE)
- throw new FJException();
- return false;
- }
-
- protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
- number = ((AsyncFib)x).number + ((AsyncFib)y).number;
- super.onComplete(x, y);
- }
-
- public void checkCompletedNormally() {
- assertEquals(expectedResult, number);
- ForkJoinTask8Test.this.checkCompletedNormally(this);
- }
- }
-
- static final class FailingAsyncFib extends BinaryAsyncAction {
- int number;
- public FailingAsyncFib(int n) {
- this.number = n;
- }
-
- public final boolean exec() {
- try {
- FailingAsyncFib f = this;
- int n = f.number;
- while (n > 1) {
- FailingAsyncFib p = f;
- FailingAsyncFib r = new FailingAsyncFib(n - 2);
- f = new FailingAsyncFib(--n);
- p.linkSubtasks(r, f);
- r.fork();
- }
- f.complete();
- }
- catch (Throwable ex) {
- compareAndSetForkJoinTaskTag(INITIAL_STATE, EXCEPTION_STATE);
- }
- if (getForkJoinTaskTag() == EXCEPTION_STATE)
- throw new FJException();
- return false;
- }
-
- protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
- completeExceptionally(new FJException());
- }
- }
-
- /**
- * invoke returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks; getRawResult returns null.
- */
- public void testInvoke() {
- testInvoke(mainPool());
- }
- public void testInvoke_Singleton() {
- testInvoke(singletonPool());
- }
- public void testInvoke(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- assertNull(f.invoke());
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * quietlyInvoke task returns when task completes normally.
- * isCompletedAbnormally and isCancelled return false for normally
- * completed tasks
- */
- public void testQuietlyInvoke() {
- testQuietlyInvoke(mainPool());
- }
- public void testQuietlyInvoke_Singleton() {
- testQuietlyInvoke(singletonPool());
- }
- public void testQuietlyInvoke(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- f.quietlyInvoke();
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * join of a forked task returns when task completes
- */
- public void testForkJoin() {
- testForkJoin(mainPool());
- }
- public void testForkJoin_Singleton() {
- testForkJoin(singletonPool());
- }
- public void testForkJoin(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertNull(f.join());
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * get of a forked task returns when task completes
- */
- public void testForkGet() {
- testForkGet(mainPool());
- }
- public void testForkGet_Singleton() {
- testForkGet(singletonPool());
- }
- public void testForkGet(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertNull(f.get());
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * timed get of a forked task returns when task completes
- */
- public void testForkTimedGet() {
- testForkTimedGet(mainPool());
- }
- public void testForkTimedGet_Singleton() {
- testForkTimedGet(singletonPool());
- }
- public void testForkTimedGet(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * timed get with null time unit throws NullPointerException
- */
- public void testForkTimedGetNullTimeUnit() {
- testForkTimedGetNullTimeUnit(mainPool());
- }
- public void testForkTimedGetNullTimeUnit_Singleton() {
- testForkTimedGet(singletonPool());
- }
- public void testForkTimedGetNullTimeUnit(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- try {
- f.get(5L, null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes
- */
- public void testForkQuietlyJoin() {
- testForkQuietlyJoin(mainPool());
- }
- public void testForkQuietlyJoin_Singleton() {
- testForkQuietlyJoin(singletonPool());
- }
- public void testForkQuietlyJoin(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * helpQuiesce returns when tasks are complete.
- * getQueuedTaskCount returns 0 when quiescent
- */
- public void testForkHelpQuiesce() {
- testForkHelpQuiesce(mainPool());
- }
- public void testForkHelpQuiesce_Singleton() {
- testForkHelpQuiesce(singletonPool());
- }
- public void testForkHelpQuiesce(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- helpQuiesce();
- assertEquals(0, getQueuedTaskCount());
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invoke task throws exception when task completes abnormally
- */
- public void testAbnormalInvoke() {
- testAbnormalInvoke(mainPool());
- }
- public void testAbnormalInvoke_Singleton() {
- testAbnormalInvoke(singletonPool());
- }
- public void testAbnormalInvoke(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib f = new FailingAsyncFib(8);
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * quietlyInvoke task returns when task completes abnormally
- */
- public void testAbnormalQuietlyInvoke() {
- testAbnormalQuietlyInvoke(mainPool());
- }
- public void testAbnormalQuietlyInvoke_Singleton() {
- testAbnormalQuietlyInvoke(singletonPool());
- }
- public void testAbnormalQuietlyInvoke(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib f = new FailingAsyncFib(8);
- f.quietlyInvoke();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * join of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkJoin() {
- testAbnormalForkJoin(mainPool());
- }
- public void testAbnormalForkJoin_Singleton() {
- testAbnormalForkJoin(singletonPool());
- }
- public void testAbnormalForkJoin(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib f = new FailingAsyncFib(8);
- assertSame(f, f.fork());
- try {
- f.join();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkGet() {
- testAbnormalForkGet(mainPool());
- }
- public void testAbnormalForkGet_Singleton() {
- testAbnormalForkJoin(singletonPool());
- }
- public void testAbnormalForkGet(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingAsyncFib f = new FailingAsyncFib(8);
- assertSame(f, f.fork());
- try {
- f.get();
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * timed get of a forked task throws exception when task completes abnormally
- */
- public void testAbnormalForkTimedGet() {
- testAbnormalForkTimedGet(mainPool());
- }
- public void testAbnormalForkTimedGet_Singleton() {
- testAbnormalForkTimedGet(singletonPool());
- }
- public void testAbnormalForkTimedGet(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() throws Exception {
- FailingAsyncFib f = new FailingAsyncFib(8);
- assertSame(f, f.fork());
- try {
- f.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- Throwable cause = success.getCause();
- assertTrue(cause instanceof FJException);
- checkCompletedAbnormally(f, cause);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * quietlyJoin of a forked task returns when task completes abnormally
- */
- public void testAbnormalForkQuietlyJoin() {
- testAbnormalForkQuietlyJoin(mainPool());
- }
- public void testAbnormalForkQuietlyJoin_Singleton() {
- testAbnormalForkQuietlyJoin(singletonPool());
- }
- public void testAbnormalForkQuietlyJoin(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib f = new FailingAsyncFib(8);
- assertSame(f, f.fork());
- f.quietlyJoin();
- assertTrue(f.getException() instanceof FJException);
- checkCompletedAbnormally(f, f.getException());
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * getPool of executing task returns its pool
- */
- public void testGetPool() {
- testGetPool(mainPool());
- }
- public void testGetPool_Singleton() {
- testGetPool(singletonPool());
- }
- public void testGetPool(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertSame(pool, getPool());
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * getPool of non-FJ task returns null
- */
- public void testGetPool2() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertNull(getPool());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * inForkJoinPool of executing task returns true
- */
- public void testInForkJoinPool() {
- testInForkJoinPool(mainPool());
- }
- public void testInForkJoinPool_Singleton() {
- testInForkJoinPool(singletonPool());
- }
- public void testInForkJoinPool(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertTrue(inForkJoinPool());
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * inForkJoinPool of non-FJ task returns false
- */
- public void testInForkJoinPool2() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- assertFalse(inForkJoinPool());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * setRawResult(null) succeeds
- */
- public void testSetRawResult() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- setRawResult(null);
- assertNull(getRawResult());
- }};
- assertNull(a.invoke());
- }
-
- /**
- * invoke task throws exception after invoking completeExceptionally
- */
- public void testCompleteExceptionally() {
- testCompleteExceptionally(mainPool());
- }
- public void testCompleteExceptionally_Singleton() {
- testCompleteExceptionally(singletonPool());
- }
- public void testCompleteExceptionally(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- f.completeExceptionally(new FJException());
- try {
- f.invoke();
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument invokes task
- */
- public void testInvokeAll1() {
- testInvokeAll1(mainPool());
- }
- public void testInvokeAll1_Singleton() {
- testInvokeAll1(singletonPool());
- }
- public void testInvokeAll1(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- invokeAll(f);
- f.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(t1, t2) invokes all task arguments
- */
- public void testInvokeAll2() {
- testInvokeAll2(mainPool());
- }
- public void testInvokeAll2_Singleton() {
- testInvokeAll2(singletonPool());
- }
- public void testInvokeAll2(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib[] tasks = {
- new AsyncFib(8),
- new AsyncFib(9),
- };
- invokeAll(tasks[0], tasks[1]);
- for (AsyncFib task : tasks) assertTrue(task.isDone());
- for (AsyncFib task : tasks) task.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument invokes tasks
- */
- public void testInvokeAll3() {
- testInvokeAll3(mainPool());
- }
- public void testInvokeAll3_Singleton() {
- testInvokeAll3(singletonPool());
- }
- public void testInvokeAll3(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib[] tasks = {
- new AsyncFib(8),
- new AsyncFib(9),
- new AsyncFib(7),
- };
- invokeAll(tasks[0], tasks[1], tasks[2]);
- for (AsyncFib task : tasks) assertTrue(task.isDone());
- for (AsyncFib task : tasks) task.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(collection) invokes all tasks in the collection
- */
- public void testInvokeAllCollection() {
- testInvokeAllCollection(mainPool());
- }
- public void testInvokeAllCollection_Singleton() {
- testInvokeAllCollection(singletonPool());
- }
- public void testInvokeAllCollection(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib[] tasks = {
- new AsyncFib(8),
- new AsyncFib(9),
- new AsyncFib(7),
- };
- invokeAll(Arrays.asList(tasks));
- for (AsyncFib task : tasks) assertTrue(task.isDone());
- for (AsyncFib task : tasks) task.checkCompletedNormally();
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(tasks) with any null task throws NullPointerException
- */
- public void testInvokeAllNullTask() {
- testInvokeAllNullTask(mainPool());
- }
- public void testInvokeAllNullTask_Singleton() {
- testInvokeAllNullTask(singletonPool());
- }
- public void testInvokeAllNullTask(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib nul = null;
- Runnable[] throwingActions = {
- () -> invokeAll(nul),
- () -> invokeAll(nul, nul),
- () -> invokeAll(new AsyncFib(8), new AsyncFib(9), nul),
- () -> invokeAll(new AsyncFib(8), nul, new AsyncFib(9)),
- () -> invokeAll(nul, new AsyncFib(8), new AsyncFib(9)),
- };
- assertThrows(NullPointerException.class, throwingActions);
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(tasks) with 1 argument throws exception if task does
- */
- public void testAbnormalInvokeAll1() {
- testAbnormalInvokeAll1(mainPool());
- }
- public void testAbnormalInvokeAll1_Singleton() {
- testAbnormalInvokeAll1(singletonPool());
- }
- public void testAbnormalInvokeAll1(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib g = new FailingAsyncFib(9);
- try {
- invokeAll(g);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(t1, t2) throw exception if any task does
- */
- public void testAbnormalInvokeAll2() {
- testAbnormalInvokeAll2(mainPool());
- }
- public void testAbnormalInvokeAll2_Singleton() {
- testAbnormalInvokeAll2(singletonPool());
- }
- public void testAbnormalInvokeAll2(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- FailingAsyncFib g = new FailingAsyncFib(9);
- ForkJoinTask[] tasks = { f, g };
- Collections.shuffle(Arrays.asList(tasks));
- try {
- invokeAll(tasks[0], tasks[1]);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(tasks) with > 2 argument throws exception if any task does
- */
- public void testAbnormalInvokeAll3() {
- testAbnormalInvokeAll3(mainPool());
- }
- public void testAbnormalInvokeAll3_Singleton() {
- testAbnormalInvokeAll3(singletonPool());
- }
- public void testAbnormalInvokeAll3(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- FailingAsyncFib g = new FailingAsyncFib(9);
- AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- Collections.shuffle(Arrays.asList(tasks));
- try {
- invokeAll(tasks[0], tasks[1], tasks[2]);
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(g, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * invokeAll(collection) throws exception if any task does
- */
- public void testAbnormalInvokeAllCollection() {
- testAbnormalInvokeAllCollection(mainPool());
- }
- public void testAbnormalInvokeAllCollection_Singleton() {
- testAbnormalInvokeAllCollection(singletonPool());
- }
- public void testAbnormalInvokeAllCollection(ForkJoinPool pool) {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- FailingAsyncFib f = new FailingAsyncFib(8);
- AsyncFib g = new AsyncFib(9);
- AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- Collections.shuffle(Arrays.asList(tasks));
- try {
- invokeAll(Arrays.asList(tasks));
- shouldThrow();
- } catch (FJException success) {
- checkCompletedAbnormally(f, success);
- }
- }};
- testInvokeOnPool(pool, a);
- }
-
- /**
- * tryUnfork returns true for most recent unexecuted task,
- * and suppresses execution
- */
- public void testTryUnfork() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertTrue(f.tryUnfork());
- helpQuiesce();
- checkNotDone(f);
- g.checkCompletedNormally();
- }};
- testInvokeOnPool(singletonPool(), a);
- }
-
- /**
- * getSurplusQueuedTaskCount returns > 0 when
- * there are more tasks than threads
- */
- public void testGetSurplusQueuedTaskCount() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib h = new AsyncFib(7);
- assertSame(h, h.fork());
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertTrue(getSurplusQueuedTaskCount() > 0);
- helpQuiesce();
- assertEquals(0, getSurplusQueuedTaskCount());
- f.checkCompletedNormally();
- g.checkCompletedNormally();
- h.checkCompletedNormally();
- }};
- testInvokeOnPool(singletonPool(), a);
- }
-
- /**
- * peekNextLocalTask returns most recent unexecuted task.
- */
- public void testPeekNextLocalTask() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(f, peekNextLocalTask());
- assertNull(f.join());
- f.checkCompletedNormally();
- helpQuiesce();
- g.checkCompletedNormally();
- }};
- testInvokeOnPool(singletonPool(), a);
- }
-
- /**
- * pollNextLocalTask returns most recent unexecuted task without
- * executing it
- */
- public void testPollNextLocalTask() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(f, pollNextLocalTask());
- helpQuiesce();
- checkNotDone(f);
- g.checkCompletedNormally();
- }};
- testInvokeOnPool(singletonPool(), a);
- }
-
- /**
- * pollTask returns an unexecuted task without executing it
- */
- public void testPollTask() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(f, pollTask());
- helpQuiesce();
- checkNotDone(f);
- g.checkCompletedNormally();
- }};
- testInvokeOnPool(singletonPool(), a);
- }
-
- /**
- * peekNextLocalTask returns least recent unexecuted task in async mode
- */
- public void testPeekNextLocalTaskAsync() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(g, peekNextLocalTask());
- assertNull(f.join());
- helpQuiesce();
- f.checkCompletedNormally();
- g.checkCompletedNormally();
- }};
- testInvokeOnPool(asyncSingletonPool(), a);
- }
-
- /**
- * pollNextLocalTask returns least recent unexecuted task without
- * executing it, in async mode
- */
- public void testPollNextLocalTaskAsync() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(g, pollNextLocalTask());
- helpQuiesce();
- f.checkCompletedNormally();
- checkNotDone(g);
- }};
- testInvokeOnPool(asyncSingletonPool(), a);
- }
-
- /**
- * pollTask returns an unexecuted task without executing it, in
- * async mode
- */
- public void testPollTaskAsync() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib g = new AsyncFib(9);
- assertSame(g, g.fork());
- AsyncFib f = new AsyncFib(8);
- assertSame(f, f.fork());
- assertSame(g, pollTask());
- helpQuiesce();
- f.checkCompletedNormally();
- checkNotDone(g);
- }};
- testInvokeOnPool(asyncSingletonPool(), a);
- }
-
- /**
- * ForkJoinTask.quietlyComplete returns when task completes
- * normally without setting a value. The most recent value
- * established by setRawResult(V) (or null by default) is returned
- * from invoke.
- */
- public void testQuietlyComplete() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- f.quietlyComplete();
- assertEquals(8, f.number);
- assertTrue(f.isDone());
- assertFalse(f.isCancelled());
- assertTrue(f.isCompletedNormally());
- assertFalse(f.isCompletedAbnormally());
- assertNull(f.getException());
- }};
- testInvokeOnPool(mainPool(), a);
- }
-
- // jdk9
-
- /**
- * pollSubmission returns unexecuted submitted task, if present
- */
- public void testPollSubmission() {
- final CountDownLatch done = new CountDownLatch(1);
- final ForkJoinTask a = ForkJoinTask.adapt(awaiter(done));
- final ForkJoinTask b = ForkJoinTask.adapt(awaiter(done));
- final ForkJoinTask c = ForkJoinTask.adapt(awaiter(done));
- final ForkJoinPool p = singletonPool();
- try (PoolCleaner cleaner = cleaner(p, done)) {
- Thread external = new Thread(new CheckedRunnable() {
- public void realRun() {
- p.execute(a);
- p.execute(b);
- p.execute(c);
- }});
- RecursiveAction s = new CheckedRecursiveAction() {
- protected void realCompute() {
- external.start();
- try {
- external.join();
- } catch (Exception ex) {
- threadUnexpectedException(ex);
- }
- assertTrue(p.hasQueuedSubmissions());
- assertTrue(Thread.currentThread() instanceof ForkJoinWorkerThread);
- ForkJoinTask r = ForkJoinTask.pollSubmission();
- assertTrue(r == a || r == b || r == c);
- assertFalse(r.isDone());
- }};
- p.invoke(s);
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
index 1616d4f..3c1fcb7 100644
--- a/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
@@ -9,10 +9,7 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
@@ -33,7 +30,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ForkJoinTaskTest.class);
+ // return new TestSuite(...);
// }
// Runs with "mainPool" use > 1 thread. singletonPool tests use 1
@@ -55,7 +52,7 @@
}
private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
- try (PoolCleaner cleaner = cleaner(pool)) {
+ try {
assertFalse(a.isDone());
assertFalse(a.isCompletedNormally());
assertFalse(a.isCompletedAbnormally());
@@ -71,6 +68,8 @@
assertFalse(a.isCancelled());
assertNull(a.getException());
assertNull(a.getRawResult());
+ } finally {
+ joinPool(pool);
}
}
@@ -103,17 +102,17 @@
{
Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
assertSame(expected, a.join());
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
Thread.interrupted();
}
{
Thread.currentThread().interrupt();
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
Thread.interrupted();
}
@@ -146,9 +145,9 @@
Thread.interrupted();
{
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
try {
@@ -184,9 +183,9 @@
Thread.interrupted();
{
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
a.quietlyJoin(); // should be no-op
- assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
try {
@@ -223,9 +222,9 @@
AtomicIntegerFieldUpdater.newUpdater(BinaryAsyncAction.class,
"controlState");
- private volatile BinaryAsyncAction parent;
+ private BinaryAsyncAction parent;
- private volatile BinaryAsyncAction sibling;
+ private BinaryAsyncAction sibling;
protected BinaryAsyncAction() {
}
@@ -260,14 +259,6 @@
super.completeExceptionally(ex);
}
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (super.cancel(mayInterruptIfRunning)) {
- completeExceptionally(new FJException());
- return true;
- }
- return false;
- }
-
public final void complete() {
BinaryAsyncAction a = this;
for (;;) {
@@ -289,12 +280,13 @@
}
public final void completeExceptionally(Throwable ex) {
- for (BinaryAsyncAction a = this;;) {
+ BinaryAsyncAction a = this;
+ while (!a.isCompletedAbnormally()) {
a.completeThisExceptionally(ex);
BinaryAsyncAction s = a.sibling;
- if (s != null && !s.isDone())
- s.completeExceptionally(ex);
- if ((a = a.parent) == null)
+ if (s != null)
+ s.cancel(false);
+ if (!a.onException() || (a = a.parent) == null)
break;
}
}
@@ -344,12 +336,15 @@
public final boolean exec() {
AsyncFib f = this;
int n = f.number;
- while (n > 1) {
- AsyncFib p = f;
- AsyncFib r = new AsyncFib(n - 2);
- f = new AsyncFib(--n);
- p.linkSubtasks(r, f);
- r.fork();
+ if (n > 1) {
+ while (n > 1) {
+ AsyncFib p = f;
+ AsyncFib r = new AsyncFib(n - 2);
+ f = new AsyncFib(--n);
+ p.linkSubtasks(r, f);
+ r.fork();
+ }
+ f.number = n;
}
f.complete();
return false;
@@ -369,12 +364,15 @@
public final boolean exec() {
FailingAsyncFib f = this;
int n = f.number;
- while (n > 1) {
- FailingAsyncFib p = f;
- FailingAsyncFib r = new FailingAsyncFib(n - 2);
- f = new FailingAsyncFib(--n);
- p.linkSubtasks(r, f);
- r.fork();
+ if (n > 1) {
+ while (n > 1) {
+ FailingAsyncFib p = f;
+ FailingAsyncFib r = new FailingAsyncFib(n - 2);
+ f = new FailingAsyncFib(--n);
+ p.linkSubtasks(r, f);
+ r.fork();
+ }
+ f.number = n;
}
f.complete();
return false;
@@ -780,27 +778,6 @@
}
/**
- * completeExceptionally(null) surprisingly has the same effect as
- * completeExceptionally(new RuntimeException())
- */
- public void testCompleteExceptionally_null() {
- RecursiveAction a = new CheckedRecursiveAction() {
- protected void realCompute() {
- AsyncFib f = new AsyncFib(8);
- f.completeExceptionally(null);
- try {
- f.invoke();
- shouldThrow();
- } catch (RuntimeException success) {
- assertSame(success.getClass(), RuntimeException.class);
- assertNull(success.getCause());
- checkCompletedAbnormally(f, success);
- }
- }};
- testInvokeOnPool(mainPool(), a);
- }
-
- /**
* invokeAll(t1, t2) invokes all task arguments
*/
public void testInvokeAll2() {
@@ -900,10 +877,8 @@
protected void realCompute() {
AsyncFib f = new AsyncFib(8);
FailingAsyncFib g = new FailingAsyncFib(9);
- ForkJoinTask[] tasks = { f, g };
- Collections.shuffle(Arrays.asList(tasks));
try {
- invokeAll(tasks);
+ invokeAll(f, g);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(g, success);
@@ -938,10 +913,8 @@
AsyncFib f = new AsyncFib(8);
FailingAsyncFib g = new FailingAsyncFib(9);
AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- Collections.shuffle(Arrays.asList(tasks));
try {
- invokeAll(tasks);
+ invokeAll(f, g, h);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(g, success);
@@ -959,11 +932,12 @@
FailingAsyncFib f = new FailingAsyncFib(8);
AsyncFib g = new AsyncFib(9);
AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- List taskList = Arrays.asList(tasks);
- Collections.shuffle(taskList);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
try {
- invokeAll(taskList);
+ invokeAll(set);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(f, success);
@@ -1570,10 +1544,8 @@
protected void realCompute() {
AsyncFib f = new AsyncFib(8);
FailingAsyncFib g = new FailingAsyncFib(9);
- ForkJoinTask[] tasks = { f, g };
- Collections.shuffle(Arrays.asList(tasks));
try {
- invokeAll(tasks);
+ invokeAll(f, g);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(g, success);
@@ -1608,10 +1580,8 @@
AsyncFib f = new AsyncFib(8);
FailingAsyncFib g = new FailingAsyncFib(9);
AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- Collections.shuffle(Arrays.asList(tasks));
try {
- invokeAll(tasks);
+ invokeAll(f, g, h);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(g, success);
@@ -1629,11 +1599,12 @@
FailingAsyncFib f = new FailingAsyncFib(8);
AsyncFib g = new AsyncFib(9);
AsyncFib h = new AsyncFib(7);
- ForkJoinTask[] tasks = { f, g, h };
- List taskList = Arrays.asList(tasks);
- Collections.shuffle(taskList);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
try {
- invokeAll(taskList);
+ invokeAll(set);
shouldThrow();
} catch (FJException success) {
checkCompletedAbnormally(f, success);
diff --git a/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
index 44d12b3..a5d8c46 100644
--- a/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
@@ -38,7 +38,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(FutureTaskTest.class);
+ // return new TestSuite(...);
// }
void checkIsDone(Future<?> f) {
@@ -272,8 +272,8 @@
for (int i = 0; i < 3; i++) {
assertTrue(task.runAndReset());
checkNotDone(task);
- assertEquals(i + 1, task.runCount());
- assertEquals(i + 1, task.runAndResetCount());
+ assertEquals(i+1, task.runCount());
+ assertEquals(i+1, task.runAndResetCount());
assertEquals(0, task.setCount());
assertEquals(0, task.setExceptionCount());
}
@@ -289,7 +289,7 @@
for (int i = 0; i < 3; i++) {
assertFalse(task.runAndReset());
assertEquals(0, task.runCount());
- assertEquals(i + 1, task.runAndResetCount());
+ assertEquals(i+1, task.runAndResetCount());
assertEquals(0, task.setCount());
assertEquals(0, task.setExceptionCount());
}
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
index fc1632c..46be906 100644
--- a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
+++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
@@ -6,21 +6,17 @@
* Pat Fisher, Mike Judd.
*/
-
package jsr166;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
- import java.security.CodeSource;
+import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
@@ -39,10 +35,7 @@
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
@@ -51,15 +44,12 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestCase;
-import junit.framework.TestResult;
import junit.framework.TestSuite;
/**
@@ -72,18 +62,18 @@
*
* <ol>
*
- * <li>All assertions in code running in generated threads must use
+ * <li> All assertions in code running in generated threads must use
* the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link
* #threadAssertEquals}, or {@link #threadAssertNull}, (not
* {@code fail}, {@code assertTrue}, etc.) It is OK (but not
* particularly recommended) for other code to use these forms too.
* Only the most typically used JUnit assertion methods are defined
- * this way, but enough to live with.
+ * this way, but enough to live with.</li>
*
- * <li>If you override {@link #setUp} or {@link #tearDown}, make sure
+ * <li> If you override {@link #setUp} or {@link #tearDown}, make sure
* to invoke {@code super.setUp} and {@code super.tearDown} within
* them. These methods are used to clear and check for thread
- * assertion failures.
+ * assertion failures.</li>
*
* <li>All delays and timeouts must use one of the constants {@code
* SHORT_DELAY_MS}, {@code SMALL_DELAY_MS}, {@code MEDIUM_DELAY_MS},
@@ -94,494 +84,63 @@
* is always discriminable as larger than SHORT and smaller than
* MEDIUM. And so on. These constants are set to conservative values,
* but even so, if there is ever any doubt, they can all be increased
- * in one spot to rerun tests on slower platforms.
+ * in one spot to rerun tests on slower platforms.</li>
*
- * <li>All threads generated must be joined inside each test case
+ * <li> All threads generated must be joined inside each test case
* method (or {@code fail} to do so) before returning from the
* method. The {@code joinPool} method can be used to do this when
- * using Executors.
+ * using Executors.</li>
*
* </ol>
*
* <p><b>Other notes</b>
* <ul>
*
- * <li>Usually, there is one testcase method per JSR166 method
+ * <li> Usually, there is one testcase method per JSR166 method
* covering "normal" operation, and then as many exception-testing
* methods as there are exceptions the method can throw. Sometimes
* there are multiple tests per JSR166 method when the different
* "normal" behaviors differ significantly. And sometimes testcases
- * cover multiple methods when they cannot be tested in isolation.
+ * cover multiple methods when they cannot be tested in
+ * isolation.</li>
*
- * <li>The documentation style for testcases is to provide as javadoc
+ * <li> The documentation style for testcases is to provide as javadoc
* a simple sentence or two describing the property that the testcase
* method purports to test. The javadocs do not say anything about how
- * the property is tested. To find out, read the code.
+ * the property is tested. To find out, read the code.</li>
*
- * <li>These tests are "conformance tests", and do not attempt to
+ * <li> These tests are "conformance tests", and do not attempt to
* test throughput, latency, scalability or other performance factors
* (see the separate "jtreg" tests for a set intended to check these
* for the most central aspects of functionality.) So, most tests use
* the smallest sensible numbers of threads, collection sizes, etc
- * needed to check basic conformance.
+ * needed to check basic conformance.</li>
*
* <li>The test classes currently do not declare inclusion in
* any particular package to simplify things for people integrating
- * them in TCK test suites.
+ * them in TCK test suites.</li>
*
- * <li>As a convenience, the {@code main} of this class (JSR166TestCase)
- * runs all JSR166 unit tests.
+ * <li> As a convenience, the {@code main} of this class (JSR166TestCase)
+ * runs all JSR166 unit tests.</li>
*
* </ul>
*/
public class JSR166TestCase extends TestCase {
- private static final boolean useSecurityManager =
- Boolean.getBoolean("jsr166.useSecurityManager");
-
- protected static final boolean expensiveTests =
- Boolean.getBoolean("jsr166.expensiveTests");
-
- /**
- * If true, also run tests that are not part of the official tck
- * because they test unspecified implementation details.
- */
- protected static final boolean testImplementationDetails =
- Boolean.getBoolean("jsr166.testImplementationDetails");
-
- /**
- * If true, report on stdout all "slow" tests, that is, ones that
- * take more than profileThreshold milliseconds to execute.
- */
- private static final boolean profileTests =
- Boolean.getBoolean("jsr166.profileTests");
-
- /**
- * The number of milliseconds that tests are permitted for
- * execution without being reported, when profileTests is set.
- */
- private static final long profileThreshold =
- Long.getLong("jsr166.profileThreshold", 100);
-
- /**
- * The number of repetitions per test (for tickling rare bugs).
- */
- private static final int runsPerTest =
- Integer.getInteger("jsr166.runsPerTest", 1);
-
- /**
- * The number of repetitions of the test suite (for finding leaks?).
- */
- private static final int suiteRuns =
- Integer.getInteger("jsr166.suiteRuns", 1);
-
- private static float systemPropertyValue(String name, float defaultValue) {
- String floatString = System.getProperty(name);
- if (floatString == null)
- return defaultValue;
- try {
- return Float.parseFloat(floatString);
- } catch (NumberFormatException ex) {
- throw new IllegalArgumentException(
- String.format("Bad float value in system property %s=%s",
- name, floatString));
- }
- }
-
- /**
- * The scaling factor to apply to standard delays used in tests.
- */
- private static final float delayFactor =
- systemPropertyValue("jsr166.delay.factor", 1.0f);
-
- /**
- * The timeout factor as used in the jtreg test harness.
- * See: http://openjdk.java.net/jtreg/tag-spec.html
- */
- private static final float jtregTestTimeoutFactor
- = systemPropertyValue("test.timeout.factor", 1.0f);
-
- public JSR166TestCase() { super(); }
- public JSR166TestCase(String name) { super(name); }
-
- /**
- * A filter for tests to run, matching strings of the form
- * methodName(className), e.g. "testInvokeAll5(ForkJoinPoolTest)"
- * Usefully combined with jsr166.runsPerTest.
- */
- private static final Pattern methodFilter = methodFilter();
-
- private static Pattern methodFilter() {
- String regex = System.getProperty("jsr166.methodFilter");
- return (regex == null) ? null : Pattern.compile(regex);
- }
-
- // Instrumentation to debug very rare, but very annoying hung test runs.
- static volatile TestCase currentTestCase;
- // static volatile int currentRun = 0;
- static {
- Runnable checkForWedgedTest = new Runnable() { public void run() {
- // Avoid spurious reports with enormous runsPerTest.
- // A single test case run should never take more than 1 second.
- // But let's cap it at the high end too ...
- final int timeoutMinutes =
- Math.min(15, Math.max(runsPerTest / 60, 1));
- for (TestCase lastTestCase = currentTestCase;;) {
- try { MINUTES.sleep(timeoutMinutes); }
- catch (InterruptedException unexpected) { break; }
- if (lastTestCase == currentTestCase) {
- System.err.printf(
- "Looks like we're stuck running test: %s%n",
- lastTestCase);
-// System.err.printf(
-// "Looks like we're stuck running test: %s (%d/%d)%n",
-// lastTestCase, currentRun, runsPerTest);
-// System.err.println("availableProcessors=" +
-// Runtime.getRuntime().availableProcessors());
-// System.err.printf("cpu model = %s%n", cpuModel());
- dumpTestThreads();
- // one stack dump is probably enough; more would be spam
- break;
- }
- lastTestCase = currentTestCase;
- }}};
- Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest");
- thread.setDaemon(true);
- thread.start();
- }
-
-// public static String cpuModel() {
-// try {
-// Matcher matcher = Pattern.compile("model name\\s*: (.*)")
-// .matcher(new String(
-// Files.readAllBytes(Paths.get("/proc/cpuinfo")), "UTF-8"));
-// matcher.find();
-// return matcher.group(1);
-// } catch (Exception ex) { return null; }
-// }
-
- public void runBare() throws Throwable {
- currentTestCase = this;
- if (methodFilter == null
- || methodFilter.matcher(toString()).find())
- super.runBare();
- }
-
- protected void runTest() throws Throwable {
- for (int i = 0; i < runsPerTest; i++) {
- // currentRun = i;
- if (profileTests)
- runTestProfiled();
- else
- super.runTest();
- }
- }
-
- protected void runTestProfiled() throws Throwable {
- for (int i = 0; i < 2; i++) {
- long startTime = System.nanoTime();
- super.runTest();
- long elapsedMillis = millisElapsedSince(startTime);
- if (elapsedMillis < profileThreshold)
- break;
- // Never report first run of any test; treat it as a
- // warmup run, notably to trigger all needed classloading,
- if (i > 0)
- System.out.printf("%n%s: %d%n", toString(), elapsedMillis);
- }
- }
-
- /**
- * Runs all JSR166 unit tests using junit.textui.TestRunner.
- */
- // android-note: Removed because no junit.textui
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
-
- // static class PithyResultPrinter extends junit.textui.ResultPrinter {
- // PithyResultPrinter(java.io.PrintStream writer) { super(writer); }
- // long runTime;
- // public void startTest(Test test) {}
- // protected void printHeader(long runTime) {
- // this.runTime = runTime; // defer printing for later
- // }
- // protected void printFooter(TestResult result) {
- // if (result.wasSuccessful()) {
- // getWriter().println("OK (" + result.runCount() + " tests)"
- // + " Time: " + elapsedTimeAsString(runTime));
- // } else {
- // getWriter().println("Time: " + elapsedTimeAsString(runTime));
- // super.printFooter(result);
- // }
- // }
- // }
-
- /**
- * Returns a TestRunner that doesn't bother with unnecessary
- * fluff, like printing a "." for each test case.
- */
- // static junit.textui.TestRunner newPithyTestRunner() {
- // junit.textui.TestRunner runner = new junit.textui.TestRunner();
- // runner.setPrinter(new PithyResultPrinter(System.out));
- // return runner;
- // }
-
- /**
- * Runs all unit tests in the given test suite.
- * Actual behavior influenced by jsr166.* system properties.
- */
- // static void main(Test suite, String[] args) {
- // if (useSecurityManager) {
- // System.err.println("Setting a permissive security manager");
- // Policy.setPolicy(permissivePolicy());
- // System.setSecurityManager(new SecurityManager());
- // }
- // for (int i = 0; i < suiteRuns; i++) {
- // TestResult result = newPithyTestRunner().doRun(suite);
- // if (!result.wasSuccessful())
- // System.exit(1);
- // System.gc();
- // System.runFinalization();
- // }
- // }
-
- public static TestSuite newTestSuite(Object... suiteOrClasses) {
- TestSuite suite = new TestSuite();
- for (Object suiteOrClass : suiteOrClasses) {
- if (suiteOrClass instanceof TestSuite)
- suite.addTest((TestSuite) suiteOrClass);
- else if (suiteOrClass instanceof Class)
- suite.addTest(new TestSuite((Class<?>) suiteOrClass));
- else
- throw new ClassCastException("not a test suite or class");
- }
- return suite;
- }
-
- public static void addNamedTestClasses(TestSuite suite,
- String... testClassNames) {
- for (String testClassName : testClassNames) {
- try {
- Class<?> testClass = Class.forName(testClassName);
- Method m = testClass.getDeclaredMethod("suite",
- new Class<?>[0]);
- suite.addTest(newTestSuite((Test)m.invoke(null)));
- } catch (Exception e) {
- throw new Error("Missing test class", e);
- }
- }
- }
-
- public static final double JAVA_CLASS_VERSION;
- public static final String JAVA_SPECIFICATION_VERSION;
- static {
- try {
- JAVA_CLASS_VERSION = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Double>() {
- public Double run() {
- return Double.valueOf(System.getProperty("java.class.version"));}});
- JAVA_SPECIFICATION_VERSION = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<String>() {
- public String run() {
- return System.getProperty("java.specification.version");}});
- } catch (Throwable t) {
- throw new Error(t);
- }
- }
-
- public static boolean atLeastJava6() { return JAVA_CLASS_VERSION >= 50.0; }
- public static boolean atLeastJava7() { return JAVA_CLASS_VERSION >= 51.0; }
- public static boolean atLeastJava8() { return JAVA_CLASS_VERSION >= 52.0; }
- public static boolean atLeastJava9() {
- return JAVA_CLASS_VERSION >= 53.0
- // As of 2015-09, java9 still uses 52.0 class file version
- || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?(9|[0-9][0-9])$");
- }
- public static boolean atLeastJava10() {
- return JAVA_CLASS_VERSION >= 54.0
- || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?[0-9][0-9]$");
- }
-
- /**
- * Collects all JSR166 unit tests as one suite.
- */
- // android-note: Removed because the CTS runner does a bad job of
- // public static Test suite() {
- // // Java7+ test classes
- // TestSuite suite = newTestSuite(
- // ForkJoinPoolTest.suite(),
- // ForkJoinTaskTest.suite(),
- // RecursiveActionTest.suite(),
- // RecursiveTaskTest.suite(),
- // LinkedTransferQueueTest.suite(),
- // PhaserTest.suite(),
- // ThreadLocalRandomTest.suite(),
- // AbstractExecutorServiceTest.suite(),
- // AbstractQueueTest.suite(),
- // AbstractQueuedSynchronizerTest.suite(),
- // AbstractQueuedLongSynchronizerTest.suite(),
- // ArrayBlockingQueueTest.suite(),
- // ArrayDequeTest.suite(),
- // AtomicBooleanTest.suite(),
- // AtomicIntegerArrayTest.suite(),
- // AtomicIntegerFieldUpdaterTest.suite(),
- // AtomicIntegerTest.suite(),
- // AtomicLongArrayTest.suite(),
- // AtomicLongFieldUpdaterTest.suite(),
- // AtomicLongTest.suite(),
- // AtomicMarkableReferenceTest.suite(),
- // AtomicReferenceArrayTest.suite(),
- // AtomicReferenceFieldUpdaterTest.suite(),
- // AtomicReferenceTest.suite(),
- // AtomicStampedReferenceTest.suite(),
- // ConcurrentHashMapTest.suite(),
- // ConcurrentLinkedDequeTest.suite(),
- // ConcurrentLinkedQueueTest.suite(),
- // ConcurrentSkipListMapTest.suite(),
- // ConcurrentSkipListSubMapTest.suite(),
- // ConcurrentSkipListSetTest.suite(),
- // ConcurrentSkipListSubSetTest.suite(),
- // CopyOnWriteArrayListTest.suite(),
- // CopyOnWriteArraySetTest.suite(),
- // CountDownLatchTest.suite(),
- // CyclicBarrierTest.suite(),
- // DelayQueueTest.suite(),
- // EntryTest.suite(),
- // ExchangerTest.suite(),
- // ExecutorsTest.suite(),
- // ExecutorCompletionServiceTest.suite(),
- // FutureTaskTest.suite(),
- // LinkedBlockingDequeTest.suite(),
- // LinkedBlockingQueueTest.suite(),
- // LinkedListTest.suite(),
- // LockSupportTest.suite(),
- // PriorityBlockingQueueTest.suite(),
- // PriorityQueueTest.suite(),
- // ReentrantLockTest.suite(),
- // ReentrantReadWriteLockTest.suite(),
- // ScheduledExecutorTest.suite(),
- // ScheduledExecutorSubclassTest.suite(),
- // SemaphoreTest.suite(),
- // SynchronousQueueTest.suite(),
- // SystemTest.suite(),
- // ThreadLocalTest.suite(),
- // ThreadPoolExecutorTest.suite(),
- // ThreadPoolExecutorSubclassTest.suite(),
- // ThreadTest.suite(),
- // TimeUnitTest.suite(),
- // TreeMapTest.suite(),
- // TreeSetTest.suite(),
- // TreeSubMapTest.suite(),
- // TreeSubSetTest.suite());
-
- // // Java8+ test classes
- // if (atLeastJava8()) {
- // String[] java8TestClassNames = {
- // "Atomic8Test",
- // "CompletableFutureTest",
- // "ConcurrentHashMap8Test",
- // "CountedCompleterTest",
- // "DoubleAccumulatorTest",
- // "DoubleAdderTest",
- // "ForkJoinPool8Test",
- // "ForkJoinTask8Test",
- // "LongAccumulatorTest",
- // "LongAdderTest",
- // "SplittableRandomTest",
- // "StampedLockTest",
- // "SubmissionPublisherTest",
- // "ThreadLocalRandom8Test",
- // };
- // addNamedTestClasses(suite, java8TestClassNames);
- // }
-
- // // Java9+ test classes
- // if (atLeastJava9()) {
- // String[] java9TestClassNames = {
- // // Currently empty, but expecting varhandle tests
- // };
- // addNamedTestClasses(suite, java9TestClassNames);
- // }
-
- // return suite;
- // }
-
- /** Returns list of junit-style test method names in given class. */
- public static ArrayList<String> testMethodNames(Class<?> testClass) {
- Method[] methods = testClass.getDeclaredMethods();
- ArrayList<String> names = new ArrayList<String>(methods.length);
- for (Method method : methods) {
- if (method.getName().startsWith("test")
- && Modifier.isPublic(method.getModifiers())
- // method.getParameterCount() requires jdk8+
- && method.getParameterTypes().length == 0) {
- names.add(method.getName());
- }
- }
- return names;
- }
-
- /**
- * Returns junit-style testSuite for the given test class, but
- * parameterized by passing extra data to each test.
- */
- public static <ExtraData> Test parameterizedTestSuite
- (Class<? extends JSR166TestCase> testClass,
- Class<ExtraData> dataClass,
- ExtraData data) {
- try {
- TestSuite suite = new TestSuite();
- Constructor c =
- testClass.getDeclaredConstructor(dataClass, String.class);
- for (String methodName : testMethodNames(testClass))
- suite.addTest((Test) c.newInstance(data, methodName));
- return suite;
- } catch (Exception e) {
- throw new Error(e);
- }
- }
-
- /**
- * Returns junit-style testSuite for the jdk8 extension of the
- * given test class, but parameterized by passing extra data to
- * each test. Uses reflection to allow compilation in jdk7.
- */
- public static <ExtraData> Test jdk8ParameterizedTestSuite
- (Class<? extends JSR166TestCase> testClass,
- Class<ExtraData> dataClass,
- ExtraData data) {
- if (atLeastJava8()) {
- String name = testClass.getName();
- String name8 = name.replaceAll("Test$", "8Test");
- if (name.equals(name8)) throw new Error(name);
- try {
- return (Test)
- Class.forName(name8)
- .getMethod("testSuite", new Class[] { dataClass })
- .invoke(null, data);
- } catch (Exception e) {
- throw new Error(e);
- }
- } else {
- return new TestSuite();
- }
- }
-
// Delays for timing-dependent tests, in milliseconds.
+ protected static final boolean expensiveTests = false;
+
public static long SHORT_DELAY_MS;
public static long SMALL_DELAY_MS;
public static long MEDIUM_DELAY_MS;
public static long LONG_DELAY_MS;
/**
- * Returns the shortest timed delay. This can be scaled up for
- * slow machines using the jsr166.delay.factor system property,
- * or via jtreg's -timeoutFactor: flag.
- * http://openjdk.java.net/jtreg/command-help.html
+ * Returns the shortest timed delay. This could
+ * be reimplemented to use for example a Property.
*/
protected long getShortDelay() {
- return (long) (50 * delayFactor * jtregTestTimeoutFactor);
+ return 50;
}
/**
@@ -603,12 +162,11 @@
}
/**
- * Returns a new Date instance representing a time at least
- * delayMillis milliseconds in the future.
+ * Returns a new Date instance representing a time delayMillis
+ * milliseconds in the future.
*/
Date delayedDate(long delayMillis) {
- // Add 1 because currentTimeMillis is known to round into the past.
- return new Date(System.currentTimeMillis() + delayMillis + 1);
+ return new Date(System.currentTimeMillis() + delayMillis);
}
/**
@@ -624,8 +182,6 @@
* the same test have no effect.
*/
public void threadRecordFailure(Throwable t) {
- System.err.println(t);
- dumpTestThreads();
threadFailure.compareAndSet(null, t);
}
@@ -633,13 +189,6 @@
setDelays();
}
- void tearDownFail(String format, Object... args) {
- String msg = toString() + ": " + String.format(format, args);
- System.err.println(msg);
- dumpTestThreads();
- throw new AssertionFailedError(msg);
- }
-
/**
* Extra checks that get done for all test cases.
*
@@ -667,16 +216,16 @@
}
if (Thread.interrupted())
- tearDownFail("interrupt status set in main thread");
+ throw new AssertionFailedError("interrupt status set in main thread");
checkForkJoinPoolThreadLeaks();
}
/**
- * Finds missing PoolCleaners
+ * Finds missing try { ... } finally { joinPool(e); }
*/
void checkForkJoinPoolThreadLeaks() throws InterruptedException {
- Thread[] survivors = new Thread[7];
+ Thread[] survivors = new Thread[5];
int count = Thread.enumerate(survivors);
for (int i = 0; i < count; i++) {
Thread thread = survivors[i];
@@ -684,15 +233,13 @@
if (name.startsWith("ForkJoinPool-")) {
// give thread some time to terminate
thread.join(LONG_DELAY_MS);
- if (thread.isAlive())
- tearDownFail("Found leaked ForkJoinPool thread thread=%s",
- thread);
+ if (!thread.isAlive()) continue;
+ thread.stop();
+ throw new AssertionFailedError
+ (String.format("Found leaked ForkJoinPool thread test=%s thread=%s%n",
+ toString(), name));
}
}
-
- if (!ForkJoinPool.commonPool()
- .awaitQuiescence(LONG_DELAY_MS, MILLISECONDS))
- tearDownFail("ForkJoin common pool thread stuck");
}
/**
@@ -705,7 +252,7 @@
fail(reason);
} catch (AssertionFailedError t) {
threadRecordFailure(t);
- throw t;
+ fail(reason);
}
}
@@ -832,148 +379,44 @@
/**
* Delays, via Thread.sleep, for the given millisecond delay, but
* if the sleep is shorter than specified, may re-sleep or yield
- * until time elapses. Ensures that the given time, as measured
- * by System.nanoTime(), has elapsed.
+ * until time elapses.
*/
static void delay(long millis) throws InterruptedException {
- long nanos = millis * (1000 * 1000);
- final long wakeupTime = System.nanoTime() + nanos;
- do {
+ long startTime = System.nanoTime();
+ long ns = millis * 1000 * 1000;
+ for (;;) {
if (millis > 0L)
Thread.sleep(millis);
else // too short to sleep
Thread.yield();
- nanos = wakeupTime - System.nanoTime();
- millis = nanos / (1000 * 1000);
- } while (nanos >= 0L);
- }
-
- /**
- * Allows use of try-with-resources with per-test thread pools.
- */
- class PoolCleaner implements AutoCloseable {
- private final ExecutorService pool;
- public PoolCleaner(ExecutorService pool) { this.pool = pool; }
- public void close() { joinPool(pool); }
- }
-
- /**
- * An extension of PoolCleaner that has an action to release the pool.
- */
- class PoolCleanerWithReleaser extends PoolCleaner {
- private final Runnable releaser;
- public PoolCleanerWithReleaser(ExecutorService pool, Runnable releaser) {
- super(pool);
- this.releaser = releaser;
+ long d = ns - (System.nanoTime() - startTime);
+ if (d > 0L)
+ millis = d / (1000 * 1000);
+ else
+ break;
}
- public void close() {
- try {
- releaser.run();
- } finally {
- super.close();
- }
- }
- }
-
- PoolCleaner cleaner(ExecutorService pool) {
- return new PoolCleaner(pool);
- }
-
- PoolCleaner cleaner(ExecutorService pool, Runnable releaser) {
- return new PoolCleanerWithReleaser(pool, releaser);
- }
-
- PoolCleaner cleaner(ExecutorService pool, CountDownLatch latch) {
- return new PoolCleanerWithReleaser(pool, releaser(latch));
- }
-
- Runnable releaser(final CountDownLatch latch) {
- return new Runnable() { public void run() {
- do { latch.countDown(); }
- while (latch.getCount() > 0);
- }};
- }
-
- PoolCleaner cleaner(ExecutorService pool, AtomicBoolean flag) {
- return new PoolCleanerWithReleaser(pool, releaser(flag));
- }
-
- Runnable releaser(final AtomicBoolean flag) {
- return new Runnable() { public void run() { flag.set(true); }};
}
/**
* Waits out termination of a thread pool or fails doing so.
*/
- void joinPool(ExecutorService pool) {
+ void joinPool(ExecutorService exec) {
try {
- pool.shutdown();
- if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)) {
- try {
- threadFail("ExecutorService " + pool +
- " did not terminate in a timely manner");
- } finally {
- // last resort, for the benefit of subsequent tests
- pool.shutdownNow();
- pool.awaitTermination(MEDIUM_DELAY_MS, MILLISECONDS);
- }
- }
+ exec.shutdown();
+ if (!exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS))
+ fail("ExecutorService " + exec +
+ " did not terminate in a timely manner");
} catch (SecurityException ok) {
// Allowed in case test doesn't have privs
} catch (InterruptedException fail) {
- threadFail("Unexpected InterruptedException");
- }
- }
-
- /** Like Runnable, but with the freedom to throw anything */
- interface Action { public void run() throws Throwable; }
-
- /**
- * Runs all the given actions in parallel, failing if any fail.
- * Useful for running multiple variants of tests that are
- * necessarily individually slow because they must block.
- */
- void testInParallel(Action ... actions) {
- ExecutorService pool = Executors.newCachedThreadPool();
- try (PoolCleaner cleaner = cleaner(pool)) {
- ArrayList<Future<?>> futures = new ArrayList<>(actions.length);
- for (final Action action : actions)
- futures.add(pool.submit(new CheckedRunnable() {
- public void realRun() throws Throwable { action.run();}}));
- for (Future<?> future : futures)
- try {
- assertNull(future.get(LONG_DELAY_MS, MILLISECONDS));
- } catch (ExecutionException ex) {
- threadUnexpectedException(ex.getCause());
- } catch (Exception ex) {
- threadUnexpectedException(ex);
- }
+ fail("Unexpected InterruptedException");
}
}
/**
- * A debugging tool to print stack traces of most threads, as jstack does.
- * Uninteresting threads are filtered out.
+ * A debugging tool to print all stack traces, as jstack does.
*/
- static void dumpTestThreads() {
- // Android-change no ThreadMXBean
- // ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
- // System.err.println("------ stacktrace dump start ------");
- // for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
- // String name = info.getThreadName();
- // if ("Signal Dispatcher".equals(name))
- // continue;
- // if ("Reference Handler".equals(name)
- // && info.getLockName().startsWith("java.lang.ref.Reference$Lock"))
- // continue;
- // if ("Finalizer".equals(name)
- // && info.getLockName().startsWith("java.lang.ref.ReferenceQueue$Lock"))
- // continue;
- // if ("checkForWedgedTest".equals(name))
- // continue;
- // System.err.print(info);
- // }
- // System.err.println("------ stacktrace dump end ------");
+ static void printAllStackTraces() {
}
/**
@@ -993,7 +436,7 @@
delay(millis);
assertTrue(thread.isAlive());
} catch (InterruptedException fail) {
- threadFail("Unexpected InterruptedException");
+ fail("Unexpected InterruptedException");
}
}
@@ -1015,7 +458,7 @@
for (Thread thread : threads)
assertTrue(thread.isAlive());
} catch (InterruptedException fail) {
- threadFail("Unexpected InterruptedException");
+ fail("Unexpected InterruptedException");
}
}
@@ -1089,12 +532,6 @@
* getPolicy/setPolicy.
*/
public void runWithPermissions(Runnable r, Permission... permissions) {
- // Android-changed - no SecurityManager
- // SecurityManager sm = System.getSecurityManager();
- // if (sm == null) {
- // r.run();
- // }
- // runWithSecurityManagerWithPermissions(r, permissions);
r.run();
}
@@ -1107,30 +544,6 @@
*/
public void runWithSecurityManagerWithPermissions(Runnable r,
Permission... permissions) {
- // Android-changed - no SecurityManager
- // SecurityManager sm = System.getSecurityManager();
- // if (sm == null) {
- // Policy savedPolicy = Policy.getPolicy();
- // try {
- // Policy.setPolicy(permissivePolicy());
- // System.setSecurityManager(new SecurityManager());
- // runWithSecurityManagerWithPermissions(r, permissions);
- // } finally {
- // System.setSecurityManager(null);
- // Policy.setPolicy(savedPolicy);
- // }
- // } else {
- // Policy savedPolicy = Policy.getPolicy();
- // AdjustablePolicy policy = new AdjustablePolicy(permissions);
- // Policy.setPolicy(policy);
-
- // try {
- // r.run();
- // } finally {
- // policy.addPermission(new SecurityPermission("setPolicy"));
- // Policy.setPolicy(savedPolicy);
- // }
- // }
r.run();
}
@@ -1235,6 +648,19 @@
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS);
}
+ void waitForThreadToEnterWaitStateNoTimeout(Thread thread) {
+ for (;;) {
+ Thread.State s = thread.getState();
+ if (s == Thread.State.BLOCKED ||
+ s == Thread.State.WAITING ||
+ s == Thread.State.TIMED_WAITING)
+ return;
+ else if (s == Thread.State.TERMINATED)
+ fail("Unexpected thread termination");
+ Thread.yield();
+ }
+ }
+
/**
* Returns the number of milliseconds since time given by
* startNanoTime, which must have been previously returned from a
@@ -1297,7 +723,7 @@
} finally {
if (t.getState() != Thread.State.TERMINATED) {
t.interrupt();
- threadFail("timed out waiting for thread to terminate");
+ fail("Test timed out");
}
}
}
@@ -1422,10 +848,7 @@
public static final String TEST_STRING = "a test string";
public static class StringTask implements Callable<String> {
- final String value;
- public StringTask() { this(TEST_STRING); }
- public StringTask(String value) { this.value = value; }
- public String call() { return value; }
+ public String call() { return TEST_STRING; }
}
public Callable<String> latchAwaitingStringTask(final CountDownLatch latch) {
@@ -1438,50 +861,24 @@
}};
}
- public Runnable countDowner(final CountDownLatch latch) {
+ public Runnable awaiter(final CountDownLatch latch) {
return new CheckedRunnable() {
public void realRun() throws InterruptedException {
- latch.countDown();
+ await(latch);
}};
}
- class LatchAwaiter extends CheckedRunnable {
- static final int NEW = 0;
- static final int RUNNING = 1;
- static final int DONE = 2;
- final CountDownLatch latch;
- int state = NEW;
- LatchAwaiter(CountDownLatch latch) { this.latch = latch; }
- public void realRun() throws InterruptedException {
- state = 1;
- await(latch);
- state = 2;
- }
- }
-
- public LatchAwaiter awaiter(CountDownLatch latch) {
- return new LatchAwaiter(latch);
- }
-
- public void await(CountDownLatch latch, long timeoutMillis) {
+ public void await(CountDownLatch latch) {
try {
- if (!latch.await(timeoutMillis, MILLISECONDS))
- fail("timed out waiting for CountDownLatch for "
- + (timeoutMillis/1000) + " sec");
+ assertTrue(latch.await(LONG_DELAY_MS, MILLISECONDS));
} catch (Throwable fail) {
threadUnexpectedException(fail);
}
}
- public void await(CountDownLatch latch) {
- await(latch, LONG_DELAY_MS);
- }
-
public void await(Semaphore semaphore) {
try {
- if (!semaphore.tryAcquire(LONG_DELAY_MS, MILLISECONDS))
- fail("timed out waiting for Semaphore for "
- + (LONG_DELAY_MS/1000) + " sec");
+ assertTrue(semaphore.tryAcquire(LONG_DELAY_MS, MILLISECONDS));
} catch (Throwable fail) {
threadUnexpectedException(fail);
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
index 789373d..62802bb 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
@@ -26,24 +26,25 @@
public class LinkedBlockingDequeTest extends JSR166TestCase {
- public static class Unbounded extends BlockingQueueTest {
- protected BlockingQueue emptyCollection() {
- return new LinkedBlockingDeque();
- }
- }
-
- public static class Bounded extends BlockingQueueTest {
- protected BlockingQueue emptyCollection() {
- return new LinkedBlockingDeque(SIZE);
- }
- }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
+ // android-note: These tests have been moved into their own separate
+ // classes to work around CTS issues.
+ //
+ // public static class Unbounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingDeque();
+ // }
+ // }
+ //
+ // public static class Bounded extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingDeque(SIZE);
+ // }
+ // }
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(LinkedBlockingDequeTest.class,
// new Unbounded().testSuite(),
@@ -86,7 +87,7 @@
public void testSize() {
LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.removeFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -151,7 +152,7 @@
*/
public void testPollLast() {
LinkedBlockingDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollLast());
@@ -190,7 +191,7 @@
*/
public void testPeekLast() {
LinkedBlockingDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.peekLast());
assertEquals(i, q.pollLast());
assertTrue(q.peekLast() == null ||
@@ -220,7 +221,7 @@
*/
public void testLastElement() {
LinkedBlockingDeque q = populatedDeque(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.getLast());
assertEquals(i, q.pollLast());
}
@@ -285,7 +286,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
- assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -300,7 +301,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
- assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -371,7 +372,7 @@
*/
public void testConstructor5() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = i;
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -418,7 +419,7 @@
assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.remainingCapacity());
assertEquals(SIZE, q.size() + q.remainingCapacity());
assertTrue(q.add(i));
}
@@ -428,8 +429,8 @@
* push(null) throws NPE
*/
public void testPushNull() {
- LinkedBlockingDeque q = new LinkedBlockingDeque(1);
try {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(1);
q.push(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -439,14 +440,14 @@
* push succeeds if not full; throws ISE if full
*/
public void testPush() {
- LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
- for (int i = 0; i < SIZE; ++i) {
- Integer x = new Integer(i);
- q.push(x);
- assertEquals(x, q.peek());
- }
- assertEquals(0, q.remainingCapacity());
try {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer x = new Integer(i);
+ q.push(x);
+ assertEquals(x, q.peek());
+ }
+ assertEquals(0, q.remainingCapacity());
q.push(new Integer(SIZE));
shouldThrow();
} catch (IllegalStateException success) {}
@@ -517,7 +518,7 @@
public void testAddAll3() {
LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -755,23 +756,25 @@
final CountDownLatch aboutToWait = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
+ long t0 = System.nanoTime();
aboutToWait.countDown();
try {
- q.poll(LONG_DELAY_MS, MILLISECONDS);
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
}
}});
aboutToWait.await();
- waitForThreadToEnterWaitState(t, LONG_DELAY_MS);
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
checkEmpty(q);
}
@@ -1052,18 +1055,17 @@
* returning timeout status
*/
public void testInterruptedTimedPollFirst() throws InterruptedException {
- final LinkedBlockingDeque q = populatedDeque(SIZE);
final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
+ LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
}
Thread.currentThread().interrupt();
try {
- q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+ q.pollFirst(SMALL_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
@@ -1074,7 +1076,6 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
await(pleaseInterrupt);
@@ -1250,7 +1251,7 @@
public void testTakeLast() throws InterruptedException {
LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i - 1, q.takeLast());
+ assertEquals(SIZE-i-1, q.takeLast());
}
}
@@ -1263,7 +1264,7 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i - 1, q.takeLast());
+ assertEquals(SIZE-i-1, q.takeLast());
}
Thread.currentThread().interrupt();
@@ -1293,7 +1294,7 @@
public void testTimedPollLast0() throws InterruptedException {
LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i - 1, q.pollLast(0, MILLISECONDS));
+ assertEquals(SIZE-i-1, q.pollLast(0, MILLISECONDS));
}
assertNull(q.pollLast(0, MILLISECONDS));
}
@@ -1305,7 +1306,7 @@
LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
long startTime = System.nanoTime();
- assertEquals(SIZE - i - 1, q.pollLast(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(SIZE-i-1, q.pollLast(LONG_DELAY_MS, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}
long startTime = System.nanoTime();
@@ -1319,14 +1320,12 @@
* returning timeout status
*/
public void testInterruptedTimedPollLast() throws InterruptedException {
- final LinkedBlockingDeque q = populatedDeque(SIZE);
final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
+ LinkedBlockingDeque q = populatedDeque(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i - 1,
- q.pollLast(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(SIZE-i-1, q.pollLast(LONG_DELAY_MS, MILLISECONDS));
}
Thread.currentThread().interrupt();
@@ -1342,15 +1341,12 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
-
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
await(pleaseInterrupt);
assertThreadStaysAlive(t);
t.interrupt();
awaitTermination(t);
- checkEmpty(q);
}
/**
@@ -1383,8 +1379,6 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
-
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
barrier.await();
@@ -1469,7 +1463,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -1482,7 +1476,7 @@
LinkedBlockingDeque q = populatedDeque(SIZE);
LinkedBlockingDeque p = populatedDeque(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -1681,23 +1675,23 @@
final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
q.add(one);
q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertFalse(q.offer(three));
- threadsStarted.await();
- assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
- assertEquals(0, q.remainingCapacity());
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- assertSame(one, q.take());
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
}
/**
@@ -1706,22 +1700,22 @@
public void testPollInExecutor() {
final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- checkEmpty(q);
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -1773,7 +1767,7 @@
final LinkedBlockingDeque q = populatedDeque(SIZE);
Thread t = new Thread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- q.put(new Integer(SIZE + 1));
+ q.put(new Integer(SIZE+1));
}});
t.start();
@@ -1798,7 +1792,7 @@
q.drainTo(l, i);
int k = (i < SIZE) ? i : SIZE;
assertEquals(k, l.size());
- assertEquals(SIZE - k, q.size());
+ assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
do {} while (q.poll() != null);
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
index faf3f18..bd37b2a 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
@@ -26,27 +26,25 @@
public class LinkedBlockingQueueTest extends JSR166TestCase {
- // android-note: These tests have been moved into their own separate
+ // android-note: These tests have been moved into their own separate
// classes to work around CTS issues.
//
// public static class Unbounded extends BlockingQueueTest {
- // protected BlockingQueue emptyCollection() {
- // return new LinkedBlockingQueue();
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedBlockingQueue();
// }
// }
-
+ //
// public static class Bounded extends BlockingQueueTest {
- // protected BlockingQueue emptyCollection() {
+ // protected BlockingQueue emptyCollection() {
// return new LinkedBlockingQueue(SIZE);
// }
// }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
//
// public static void main(String[] args) {
- // main(suite(), args);
+ // main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(LinkedBlockingQueueTest.class,
// new Unbounded().testSuite(),
@@ -115,7 +113,7 @@
*/
public void testConstructor5() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -162,7 +160,7 @@
assertEquals(i, q.remove());
}
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.remainingCapacity());
assertEquals(SIZE, q.size() + q.remainingCapacity());
assertTrue(q.add(i));
}
@@ -209,7 +207,7 @@
public void testAddAll3() {
LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -447,23 +445,25 @@
final CountDownLatch aboutToWait = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
+ long t0 = System.nanoTime();
aboutToWait.countDown();
try {
- q.poll(LONG_DELAY_MS, MILLISECONDS);
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
}
}});
- await(aboutToWait);
- waitForThreadToEnterWaitState(t, LONG_DELAY_MS);
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
checkEmpty(q);
}
@@ -579,7 +579,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -592,7 +592,7 @@
LinkedBlockingQueue q = populatedQueue(SIZE);
LinkedBlockingQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -727,23 +727,23 @@
final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
q.add(one);
q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertFalse(q.offer(three));
- threadsStarted.await();
- assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
- assertEquals(0, q.remainingCapacity());
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- assertSame(one, q.take());
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
}
/**
@@ -752,22 +752,22 @@
public void testPollInExecutor() {
final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- checkEmpty(q);
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -819,7 +819,7 @@
final LinkedBlockingQueue q = populatedQueue(SIZE);
Thread t = new Thread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- q.put(new Integer(SIZE + 1));
+ q.put(new Integer(SIZE+1));
}});
t.start();
@@ -844,7 +844,7 @@
q.drainTo(l, i);
int k = (i < SIZE) ? i : SIZE;
assertEquals(k, l.size());
- assertEquals(SIZE - k, q.size());
+ assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
do {} while (q.poll() != null);
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedListTest.java b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
index 9c971b4..9d9481d 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
@@ -25,7 +25,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(LinkedListTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -91,7 +91,7 @@
public void testSize() {
LinkedList q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.remove();
}
for (int i = 0; i < SIZE; ++i) {
@@ -106,8 +106,6 @@
public void testOfferNull() {
LinkedList q = new LinkedList();
q.offer(null);
- assertNull(q.get(0));
- assertTrue(q.contains(null));
}
/**
@@ -134,8 +132,8 @@
* addAll(null) throws NPE
*/
public void testAddAll1() {
- LinkedList q = new LinkedList();
try {
+ LinkedList q = new LinkedList();
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -247,14 +245,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove((Integer)i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove((Integer)i));
assertFalse(q.contains(i));
- assertFalse(q.remove((Integer)(i + 1)));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove((Integer)(i+1)));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -313,7 +311,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -326,7 +324,7 @@
LinkedList q = populatedQueue(SIZE);
LinkedList p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -551,7 +549,7 @@
*/
public void testPollLast() {
LinkedList q = populatedQueue(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollLast());
@@ -576,7 +574,7 @@
*/
public void testPeekLast() {
LinkedList q = populatedQueue(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.peekLast());
assertEquals(i, q.pollLast());
assertTrue(q.peekLast() == null ||
@@ -602,7 +600,7 @@
*/
public void testLastElement() {
LinkedList q = populatedQueue(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.getLast());
assertEquals(i, q.pollLast());
}
@@ -623,7 +621,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeFirstOccurrence(new Integer(i)));
- assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -638,7 +636,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.removeLastOccurrence(new Integer(i)));
- assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
index c712592..8d3f276 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
@@ -25,33 +25,30 @@
import junit.framework.Test;
@SuppressWarnings({"unchecked", "rawtypes"})
-public class LinkedTransferQueueTest extends JSR166TestCase {
- static class Implementation implements CollectionImplementation {
- public Class<?> klazz() { return LinkedTransferQueue.class; }
- public Collection emptyCollection() { return new LinkedTransferQueue(); }
- public Object makeElement(int i) { return i; }
- public boolean isConcurrent() { return true; }
- public boolean permitsNulls() { return false; }
- }
+// android-changed: Extend BlockingQueueTest directly.
+public class LinkedTransferQueueTest extends BlockingQueueTest {
- public static class Generic extends BlockingQueueTest {
- protected BlockingQueue emptyCollection() {
- return new LinkedTransferQueue();
- }
- }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
+ // android-changed: Extend BlockingQueueTest directly.
+ //
+ // public static class Generic extends BlockingQueueTest {
+ // protected BlockingQueue emptyCollection() {
+ // return new LinkedTransferQueue();
+ // }
+ // }
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(LinkedTransferQueueTest.class,
- // new Generic().testSuite(),
- // CollectionTest.testSuite(new Implementation()));
+ // new Generic().testSuite());
// }
+ protected BlockingQueue emptyCollection() {
+ return new LinkedTransferQueue();
+ }
+
/**
* Constructor builds new queue with size being zero and empty
* being true
@@ -90,7 +87,7 @@
*/
public void testConstructor4() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = i;
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -144,8 +141,8 @@
* addAll(this) throws IllegalArgumentException
*/
public void testAddAllSelf() {
- LinkedTransferQueue q = populatedQueue(SIZE);
try {
+ LinkedTransferQueue q = populatedQueue(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -156,11 +153,12 @@
* NullPointerException after possibly adding some elements
*/
public void testAddAll3() {
- LinkedTransferQueue q = new LinkedTransferQueue();
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = i;
try {
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE - 1; ++i) {
+ ints[i] = i;
+ }
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -267,12 +265,12 @@
*/
public void testTimedPoll() throws InterruptedException {
LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
- long startTime = System.nanoTime();
- for (int i = 0; i < SIZE; ++i)
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
-
- startTime = System.nanoTime();
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
assertNull(q.poll(timeoutMillis(), MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
checkEmpty(q);
@@ -287,21 +285,25 @@
final CountDownLatch aboutToWait = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
- for (int i = 0; i < SIZE; ++i)
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
aboutToWait.countDown();
try {
- q.poll(LONG_DELAY_MS, MILLISECONDS);
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
shouldThrow();
- } catch (InterruptedException success) {}
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
}});
aboutToWait.await();
- waitForThreadToEnterWaitState(t);
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
checkEmpty(q);
}
@@ -313,18 +315,19 @@
final BlockingQueue<Integer> q = populatedQueue(SIZE);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
Thread.currentThread().interrupt();
- for (int i = 0; i < SIZE; ++i)
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
try {
- q.poll(LONG_DELAY_MS, MILLISECONDS);
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {}
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
checkEmpty(q);
}
@@ -595,24 +598,22 @@
public void testOfferInExecutor() {
final LinkedTransferQueue q = new LinkedTransferQueue();
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
+ ExecutorService executor = Executors.newFixedThreadPool(2);
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- long startTime = System.nanoTime();
- assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- assertSame(one, q.take());
- checkEmpty(q);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ checkEmpty(q);
+ }});
+
+ joinPool(executor);
}
/**
@@ -621,25 +622,23 @@
public void testPollInExecutor() {
final LinkedTransferQueue q = new LinkedTransferQueue();
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
+ ExecutorService executor = Executors.newFixedThreadPool(2);
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- long startTime = System.nanoTime();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
- checkEmpty(q);
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -700,7 +699,7 @@
assertTrue(l.size() >= SIZE);
for (int i = 0; i < SIZE; ++i)
assertEquals(i, l.get(i));
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
assertTrue(q.size() + l.size() >= SIZE);
}
@@ -737,15 +736,14 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- long startTime = System.nanoTime();
assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
assertEquals(0, q.getWaitingConsumerCount());
assertFalse(q.hasWaitingConsumer());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
threadStarted.await();
- waitForThreadToEnterWaitState(t);
+ // waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ waitForThreadToEnterWaitStateNoTimeout(t);
assertEquals(1, q.getWaitingConsumerCount());
assertTrue(q.hasWaitingConsumer());
@@ -753,7 +751,7 @@
assertEquals(0, q.getWaitingConsumerCount());
assertFalse(q.hasWaitingConsumer());
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -784,11 +782,12 @@
}});
threadStarted.await();
- waitForThreadToEnterWaitState(t);
+ // waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ waitForThreadToEnterWaitStateNoTimeout(t);
assertEquals(1, q.size());
assertSame(five, q.poll());
checkEmpty(q);
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -844,7 +843,7 @@
assertEquals(1, q.size());
assertTrue(q.offer(three));
assertSame(four, q.poll());
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -867,15 +866,15 @@
assertEquals(1, q.size());
assertSame(four, q.take());
checkEmpty(q);
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
* tryTransfer(null) throws NullPointerException
*/
public void testTryTransfer1() {
- final LinkedTransferQueue q = new LinkedTransferQueue();
try {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
q.tryTransfer(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -909,11 +908,9 @@
assertTrue(q.tryTransfer(hotPotato));
}});
- long startTime = System.nanoTime();
- assertSame(hotPotato, q.poll(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertSame(hotPotato, q.poll(MEDIUM_DELAY_MS, MILLISECONDS));
checkEmpty(q);
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -935,7 +932,7 @@
assertSame(q.take(), hotPotato);
checkEmpty(q);
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -948,7 +945,6 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
Thread.currentThread().interrupt();
try {
q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
@@ -962,7 +958,6 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
await(pleaseInterrupt);
@@ -980,10 +975,10 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
assertFalse(q.tryTransfer(new Object(),
timeoutMillis(), MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ assertTrue(millisElapsedSince(t0) >= timeoutMillis());
checkEmpty(q);
}});
@@ -1001,9 +996,7 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
- assertTrue(q.tryTransfer(five, LONG_DELAY_MS, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(q.tryTransfer(five, MEDIUM_DELAY_MS, MILLISECONDS));
checkEmpty(q);
}});
@@ -1013,7 +1006,7 @@
assertSame(four, q.poll());
assertSame(five, q.poll());
checkEmpty(q);
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -1024,9 +1017,9 @@
final LinkedTransferQueue q = new LinkedTransferQueue();
assertTrue(q.offer(four));
assertEquals(1, q.size());
- long startTime = System.nanoTime();
+ long t0 = System.nanoTime();
assertFalse(q.tryTransfer(five, timeoutMillis(), MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ assertTrue(millisElapsedSince(t0) >= timeoutMillis());
assertEquals(1, q.size());
assertSame(four, q.poll());
assertNull(q.poll());
diff --git a/jsr166-tests/src/test/java/jsr166/LockSupportTest.java b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
index b3a8ed8..8347b08 100644
--- a/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
@@ -26,15 +26,9 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(LockSupportTest.class);
+ // return new TestSuite(...);
// }
- static {
- // 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;
- }
-
/**
* Returns the blocker object used by tests in this file.
* Any old object will do; we'll return a convenient one.
diff --git a/jsr166-tests/src/test/java/jsr166/LongAccumulatorTest.java b/jsr166-tests/src/test/java/jsr166/LongAccumulatorTest.java
deleted file mode 100644
index 5dd52e9..0000000
--- a/jsr166-tests/src/test/java/jsr166/LongAccumulatorTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Phaser;
-import java.util.concurrent.atomic.LongAccumulator;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class LongAccumulatorTest extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(LongAccumulatorTest.class);
- // }
-
- /**
- * default constructed initializes to zero
- */
- public void testConstructor() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals(0, ai.get());
- }
-
- /**
- * accumulate accumulates given value to current, and get returns current value
- */
- public void testAccumulateAndGet() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- ai.accumulate(2);
- assertEquals(2, ai.get());
- ai.accumulate(-4);
- assertEquals(2, ai.get());
- ai.accumulate(4);
- assertEquals(4, ai.get());
- }
-
- /**
- * reset() causes subsequent get() to return zero
- */
- public void testReset() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- ai.accumulate(2);
- assertEquals(2, ai.get());
- ai.reset();
- assertEquals(0, ai.get());
- }
-
- /**
- * getThenReset() returns current value; subsequent get() returns zero
- */
- public void testGetThenReset() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- ai.accumulate(2);
- assertEquals(2, ai.get());
- assertEquals(2, ai.getThenReset());
- assertEquals(0, ai.get());
- }
-
- /**
- * toString returns current value.
- */
- public void testToString() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals("0", ai.toString());
- ai.accumulate(1);
- assertEquals(Long.toString(1), ai.toString());
- }
-
- /**
- * intValue returns current value.
- */
- public void testIntValue() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals(0, ai.intValue());
- ai.accumulate(1);
- assertEquals(1, ai.intValue());
- }
-
- /**
- * longValue returns current value.
- */
- public void testLongValue() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals(0, ai.longValue());
- ai.accumulate(1);
- assertEquals(1, ai.longValue());
- }
-
- /**
- * floatValue returns current value.
- */
- public void testFloatValue() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals(0.0f, ai.floatValue());
- ai.accumulate(1);
- assertEquals(1.0f, ai.floatValue());
- }
-
- /**
- * doubleValue returns current value.
- */
- public void testDoubleValue() {
- LongAccumulator ai = new LongAccumulator(Long::max, 0L);
- assertEquals(0.0, ai.doubleValue());
- ai.accumulate(1);
- assertEquals(1.0, ai.doubleValue());
- }
-
- /**
- * accumulates by multiple threads produce correct result
- */
- public void testAccumulateAndGetMT() {
- final int incs = 1000000;
- final int nthreads = 4;
- final ExecutorService pool = Executors.newCachedThreadPool();
- LongAccumulator a = new LongAccumulator(Long::max, 0L);
- Phaser phaser = new Phaser(nthreads + 1);
- for (int i = 0; i < nthreads; ++i)
- pool.execute(new AccTask(a, phaser, incs));
- phaser.arriveAndAwaitAdvance();
- phaser.arriveAndAwaitAdvance();
- long expected = incs - 1;
- long result = a.get();
- assertEquals(expected, result);
- pool.shutdown();
- }
-
- static final class AccTask implements Runnable {
- final LongAccumulator acc;
- final Phaser phaser;
- final int incs;
- volatile long result;
- AccTask(LongAccumulator acc, Phaser phaser, int incs) {
- this.acc = acc;
- this.phaser = phaser;
- this.incs = incs;
- }
-
- public void run() {
- phaser.arriveAndAwaitAdvance();
- LongAccumulator a = acc;
- for (int i = 0; i < incs; ++i)
- a.accumulate(i);
- result = a.get();
- phaser.arrive();
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/LongAdderTest.java b/jsr166-tests/src/test/java/jsr166/LongAdderTest.java
deleted file mode 100644
index 800a9c8..0000000
--- a/jsr166-tests/src/test/java/jsr166/LongAdderTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.LongAdder;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class LongAdderTest extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(LongAdderTest.class);
- // }
-
- /**
- * default constructed initializes to zero
- */
- public void testConstructor() {
- LongAdder ai = new LongAdder();
- assertEquals(0, ai.sum());
- }
-
- /**
- * add adds given value to current, and sum returns current value
- */
- public void testAddAndSum() {
- LongAdder ai = new LongAdder();
- ai.add(2);
- assertEquals(2, ai.sum());
- ai.add(-4);
- assertEquals(-2, ai.sum());
- }
-
- /**
- * decrement decrements and sum returns current value
- */
- public void testDecrementAndsum() {
- LongAdder ai = new LongAdder();
- ai.decrement();
- assertEquals(-1, ai.sum());
- ai.decrement();
- assertEquals(-2, ai.sum());
- }
-
- /**
- * incrementAndGet increments and returns current value
- */
- public void testIncrementAndsum() {
- LongAdder ai = new LongAdder();
- ai.increment();
- assertEquals(1, ai.sum());
- ai.increment();
- assertEquals(2, ai.sum());
- }
-
- /**
- * reset() causes subsequent sum() to return zero
- */
- public void testReset() {
- LongAdder ai = new LongAdder();
- ai.add(2);
- assertEquals(2, ai.sum());
- ai.reset();
- assertEquals(0, ai.sum());
- }
-
- /**
- * sumThenReset() returns sum; subsequent sum() returns zero
- */
- public void testSumThenReset() {
- LongAdder ai = new LongAdder();
- ai.add(2);
- assertEquals(2, ai.sum());
- assertEquals(2, ai.sumThenReset());
- assertEquals(0, ai.sum());
- }
-
- /**
- * a deserialized serialized adder holds same value
- */
- public void testSerialization() throws Exception {
- LongAdder x = new LongAdder();
- LongAdder y = serialClone(x);
- assertNotSame(x, y);
- x.add(-22);
- LongAdder z = serialClone(x);
- assertNotSame(y, z);
- assertEquals(-22, x.sum());
- assertEquals(0, y.sum());
- assertEquals(-22, z.sum());
- }
-
- /**
- * toString returns current value.
- */
- public void testToString() {
- LongAdder ai = new LongAdder();
- assertEquals("0", ai.toString());
- ai.increment();
- assertEquals(Long.toString(1), ai.toString());
- }
-
- /**
- * intValue returns current value.
- */
- public void testIntValue() {
- LongAdder ai = new LongAdder();
- assertEquals(0, ai.intValue());
- ai.increment();
- assertEquals(1, ai.intValue());
- }
-
- /**
- * longValue returns current value.
- */
- public void testLongValue() {
- LongAdder ai = new LongAdder();
- assertEquals(0, ai.longValue());
- ai.increment();
- assertEquals(1, ai.longValue());
- }
-
- /**
- * floatValue returns current value.
- */
- public void testFloatValue() {
- LongAdder ai = new LongAdder();
- assertEquals(0.0f, ai.floatValue());
- ai.increment();
- assertEquals(1.0f, ai.floatValue());
- }
-
- /**
- * doubleValue returns current value.
- */
- public void testDoubleValue() {
- LongAdder ai = new LongAdder();
- assertEquals(0.0, ai.doubleValue());
- ai.increment();
- assertEquals(1.0, ai.doubleValue());
- }
-
- /**
- * adds by multiple threads produce correct sum
- */
- public void testAddAndSumMT() throws Throwable {
- final int incs = 1000000;
- final int nthreads = 4;
- final ExecutorService pool = Executors.newCachedThreadPool();
- LongAdder a = new LongAdder();
- CyclicBarrier barrier = new CyclicBarrier(nthreads + 1);
- for (int i = 0; i < nthreads; ++i)
- pool.execute(new AdderTask(a, barrier, incs));
- barrier.await();
- barrier.await();
- long total = (long)nthreads * incs;
- long sum = a.sum();
- assertEquals(sum, total);
- pool.shutdown();
- }
-
- static final class AdderTask implements Runnable {
- final LongAdder adder;
- final CyclicBarrier barrier;
- final int incs;
- volatile long result;
- AdderTask(LongAdder adder, CyclicBarrier barrier, int incs) {
- this.adder = adder;
- this.barrier = barrier;
- this.incs = incs;
- }
-
- public void run() {
- try {
- barrier.await();
- LongAdder a = adder;
- for (int i = 0; i < incs; ++i)
- a.add(1L);
- result = a.sum();
- barrier.await();
- } catch (Throwable t) { throw new Error(t); }
- }
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/PhaserTest.java b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
index 673e556..42d72f4 100644
--- a/jsr166-tests/src/test/java/jsr166/PhaserTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
@@ -28,7 +28,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(PhaserTest.class);
+ // return new TestSuite(...);
// }
private static final int maxParties = 65535;
@@ -342,8 +342,8 @@
* registered or unarrived parties would become negative
*/
public void testArriveAndDeregister1() {
- Phaser phaser = new Phaser();
try {
+ Phaser phaser = new Phaser();
phaser.arriveAndDeregister();
shouldThrow();
} catch (IllegalStateException success) {}
@@ -629,11 +629,11 @@
threads.add(newStartedThread(new CheckedRunnable() {
public void realRun() {
for (int k = 0; k < 3; k++) {
- assertEquals(2 * k + 1, phaser.arriveAndAwaitAdvance());
+ assertEquals(2*k+1, phaser.arriveAndAwaitAdvance());
count.incrementAndGet();
- assertEquals(2 * k + 1, phaser.arrive());
- assertEquals(2 * k + 2, phaser.awaitAdvance(2 * k + 1));
- assertEquals(4 * (k + 1), count.get());
+ assertEquals(2*k+1, phaser.arrive());
+ assertEquals(2*k+2, phaser.awaitAdvance(2*k+1));
+ assertEquals(4*(k+1), count.get());
}}}));
for (Thread thread : threads)
@@ -689,7 +689,7 @@
for (Phaser phaser : phasers) {
assertEquals(-42, phaser.awaitAdvance(-42));
assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
- assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
}
for (Phaser child : onePartyChildren)
@@ -697,10 +697,10 @@
for (Phaser phaser : phasers) {
assertEquals(-42, phaser.awaitAdvance(-42));
assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
- assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, phaser.awaitAdvance(0));
assertEquals(1, phaser.awaitAdvanceInterruptibly(0));
- assertEquals(1, phaser.awaitAdvanceInterruptibly(0, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(1, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS));
}
for (Phaser child : onePartyChildren)
@@ -708,13 +708,13 @@
for (Phaser phaser : phasers) {
assertEquals(-42, phaser.awaitAdvance(-42));
assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
- assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
assertEquals(2, phaser.awaitAdvance(0));
assertEquals(2, phaser.awaitAdvanceInterruptibly(0));
- assertEquals(2, phaser.awaitAdvanceInterruptibly(0, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS));
assertEquals(2, phaser.awaitAdvance(1));
assertEquals(2, phaser.awaitAdvanceInterruptibly(1));
- assertEquals(2, phaser.awaitAdvanceInterruptibly(1, MEDIUM_DELAY_MS, MILLISECONDS));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(1, SMALL_DELAY_MS, MILLISECONDS));
}
}
@@ -752,8 +752,8 @@
* unarrived parties
*/
public void testArriveAndAwaitAdvance1() {
- Phaser phaser = new Phaser();
try {
+ Phaser phaser = new Phaser();
phaser.arriveAndAwaitAdvance();
shouldThrow();
} catch (IllegalStateException success) {}
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
index 41b06f5..64c3b3a 100644
--- a/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
@@ -27,7 +27,7 @@
public class PriorityBlockingQueueTest extends JSR166TestCase {
- // android-note: These tests have been moved into their own separate
+ // android-note: These tests have been moved into their own separate
// classes to work around CTS issues.
//
// public static class Generic extends BlockingQueueTest {
@@ -35,19 +35,17 @@
// return new PriorityBlockingQueue();
// }
// }
-
+ //
// public static class InitialCapacity extends BlockingQueueTest {
// protected BlockingQueue emptyCollection() {
// return new PriorityBlockingQueue(SIZE);
// }
// }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(PriorityBlockingQueueTest.class,
// new Generic().testSuite(),
@@ -69,7 +67,7 @@
PriorityBlockingQueue<Integer> q =
new PriorityBlockingQueue<Integer>(n);
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new Integer(i)));
@@ -123,7 +121,7 @@
*/
public void testConstructor5() {
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = i;
Collection<Integer> elements = Arrays.asList(ints);
try {
@@ -155,7 +153,7 @@
for (int i = 0; i < SIZE; ++i)
ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
assertEquals(ints[i], q.poll());
}
@@ -227,8 +225,8 @@
* addAll(this) throws IAE
*/
public void testAddAllSelf() {
- PriorityBlockingQueue q = populatedQueue(SIZE);
try {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
q.addAll(q);
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -239,11 +237,11 @@
* possibly adding some elements
*/
public void testAddAll3() {
- PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -255,7 +253,7 @@
public void testAddAll5() {
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
ints[i] = new Integer(i);
PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
assertFalse(q.addAll(Arrays.asList(empty)));
@@ -400,23 +398,25 @@
final CountDownLatch aboutToWait = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
}
+ long t0 = System.nanoTime();
aboutToWait.countDown();
try {
q.poll(LONG_DELAY_MS, MILLISECONDS);
shouldThrow();
} catch (InterruptedException success) {
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
}
}});
aboutToWait.await();
- waitForThreadToEnterWaitState(t, LONG_DELAY_MS);
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
}
/**
@@ -517,7 +517,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -530,7 +530,7 @@
PriorityBlockingQueue q = populatedQueue(SIZE);
PriorityBlockingQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
@@ -629,22 +629,22 @@
public void testPollInExecutor() {
final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- checkEmpty(q);
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -694,7 +694,7 @@
final PriorityBlockingQueue q = populatedQueue(SIZE);
Thread t = new Thread(new CheckedRunnable() {
public void realRun() {
- q.put(new Integer(SIZE + 1));
+ q.put(new Integer(SIZE+1));
}});
t.start();
@@ -711,7 +711,7 @@
* drainTo(c, n) empties first min(n, size) elements of queue into c
*/
public void testDrainToN() {
- PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE * 2);
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE*2);
for (int i = 0; i < SIZE + 2; ++i) {
for (int j = 0; j < SIZE; j++)
assertTrue(q.offer(new Integer(j)));
@@ -719,7 +719,7 @@
q.drainTo(l, i);
int k = (i < SIZE) ? i : SIZE;
assertEquals(k, l.size());
- assertEquals(SIZE - k, q.size());
+ assertEquals(SIZE-k, q.size());
for (int j = 0; j < k; ++j)
assertEquals(l.get(j), new Integer(j));
do {} while (q.poll() != null);
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
index f64ef68..88cdd37 100644
--- a/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
@@ -27,7 +27,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(PriorityQueueTest.class);
+ // return new TestSuite(...);
// }
static class MyReverseComparator implements Comparator {
@@ -43,7 +43,7 @@
private PriorityQueue<Integer> populatedQueue(int n) {
PriorityQueue<Integer> q = new PriorityQueue<Integer>(n);
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.offer(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.offer(new Integer(i)));
@@ -84,7 +84,8 @@
*/
public void testConstructor4() {
try {
- new PriorityQueue(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new PriorityQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -93,10 +94,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new PriorityQueue(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -125,7 +126,7 @@
for (int i = 0; i < SIZE; ++i)
ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
assertEquals(ints[i], q.poll());
}
@@ -149,7 +150,7 @@
public void testSize() {
PriorityQueue q = populatedQueue(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.remove();
}
for (int i = 0; i < SIZE; ++i) {
@@ -162,8 +163,8 @@
* offer(null) throws NPE
*/
public void testOfferNull() {
- PriorityQueue q = new PriorityQueue(1);
try {
+ PriorityQueue q = new PriorityQueue(1);
q.offer(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -173,8 +174,8 @@
* add(null) throws NPE
*/
public void testAddNull() {
- PriorityQueue q = new PriorityQueue(1);
try {
+ PriorityQueue q = new PriorityQueue(1);
q.add(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -216,8 +217,8 @@
* addAll(null) throws NPE
*/
public void testAddAll1() {
- PriorityQueue q = new PriorityQueue(1);
try {
+ PriorityQueue q = new PriorityQueue(1);
q.addAll(null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -227,9 +228,10 @@
* addAll of a collection with null elements throws NPE
*/
public void testAddAll2() {
- PriorityQueue q = new PriorityQueue(SIZE);
try {
- q.addAll(Arrays.asList(new Integer[SIZE]));
+ PriorityQueue q = new PriorityQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -239,11 +241,11 @@
* possibly adding some elements
*/
public void testAddAll3() {
- PriorityQueue q = new PriorityQueue(SIZE);
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ PriorityQueue q = new PriorityQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -256,7 +258,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1-i);
PriorityQueue q = new PriorityQueue(SIZE);
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -327,14 +329,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -393,7 +395,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.remove();
}
}
@@ -406,7 +408,7 @@
PriorityQueue q = populatedQueue(SIZE);
PriorityQueue p = populatedQueue(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.remove());
assertFalse(q.contains(x));
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
index c8e33be..1c3bba8 100644
--- a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
@@ -32,7 +32,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(RecursiveActionTest.class);
+ // return new TestSuite(...);
// }
private static ForkJoinPool mainPool() {
@@ -50,12 +50,14 @@
}
private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
- try (PoolCleaner cleaner = cleaner(pool)) {
+ try {
checkNotDone(a);
assertNull(pool.invoke(a));
checkCompletedNormally(a);
+ } finally {
+ joinPool(pool);
}
}
@@ -427,12 +429,12 @@
t = newStartedThread(r);
testInvokeOnPool(mainPool(), a);
- awaitTermination(t);
+ awaitTermination(t, LONG_DELAY_MS);
a.reinitialize();
t = newStartedThread(r);
testInvokeOnPool(singletonPool(), a);
- awaitTermination(t);
+ awaitTermination(t, LONG_DELAY_MS);
}
/**
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
index 2c07c2a..7783370 100644
--- a/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
@@ -28,7 +28,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(RecursiveTaskTest.class);
+ // return new TestSuite(...);
// }
private static ForkJoinPool mainPool() {
@@ -46,13 +46,15 @@
}
private <T> T testInvokeOnPool(ForkJoinPool pool, RecursiveTask<T> a) {
- try (PoolCleaner cleaner = cleaner(pool)) {
+ try {
checkNotDone(a);
T result = pool.invoke(a);
checkCompletedNormally(a, result);
return result;
+ } finally {
+ joinPool(pool);
}
}
@@ -333,8 +335,6 @@
FibTask f = new FibTask(8);
assertSame(f, f.fork());
helpQuiesce();
- while (!f.isDone()) // wait out race
- ;
assertEquals(0, getQueuedTaskCount());
checkCompletedNormally(f, 21);
return NoResult;
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
index 0024ff3..17eaf76 100644
--- a/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
@@ -30,9 +30,8 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ReentrantLockTest.class);
+ // return new TestSuite(...);
// }
-
/**
* A checked runnable calling lockInterruptibly
*/
@@ -151,7 +150,7 @@
enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
- * Awaits condition "indefinitely" using the specified AwaitMethod.
+ * Awaits condition using the specified AwaitMethod.
*/
void await(Condition c, AwaitMethod awaitMethod)
throws InterruptedException {
@@ -164,10 +163,9 @@
assertTrue(c.await(timeoutMillis, MILLISECONDS));
break;
case awaitNanos:
- long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
- long nanosRemaining = c.awaitNanos(timeoutNanos);
- assertTrue(nanosRemaining > timeoutNanos / 2);
- assertTrue(nanosRemaining <= timeoutNanos);
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining > 0);
break;
case awaitUntil:
assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
@@ -430,7 +428,7 @@
}
for (int i = SIZE; i > 0; i--) {
lock.unlock();
- assertEquals(i - 1, lock.getHoldCount());
+ assertEquals(i-1, lock.getHoldCount());
}
}
@@ -570,11 +568,11 @@
final ReentrantLock lock = new ReentrantLock(fair);
final Condition c = lock.newCondition();
lock.lock();
- // We shouldn't assume that nanoTime and currentTimeMillis
- // use the same time source, so don't use nanoTime here.
- java.util.Date delayedDate = delayedDate(timeoutMillis());
- assertFalse(c.awaitUntil(delayedDate));
- assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ java.util.Date d = new java.util.Date();
+ assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.unlock();
} catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
index 918f45d..7ef8ea3 100644
--- a/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
@@ -31,7 +31,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ReentrantReadWriteLockTest.class);
+ // return new TestSuite(...);
// }
/**
@@ -160,26 +160,24 @@
enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
- * Awaits condition "indefinitely" using the specified AwaitMethod.
+ * Awaits condition using the specified AwaitMethod.
*/
void await(Condition c, AwaitMethod awaitMethod)
throws InterruptedException {
- long timeoutMillis = 2 * LONG_DELAY_MS;
switch (awaitMethod) {
case await:
c.await();
break;
case awaitTimed:
- assertTrue(c.await(timeoutMillis, MILLISECONDS));
+ assertTrue(c.await(2 * LONG_DELAY_MS, MILLISECONDS));
break;
case awaitNanos:
- long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
- long nanosRemaining = c.awaitNanos(timeoutNanos);
- assertTrue(nanosRemaining > timeoutNanos / 2);
- assertTrue(nanosRemaining <= timeoutNanos);
+ long nanosRemaining = c.awaitNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS));
+ assertTrue(nanosRemaining > 0);
break;
case awaitUntil:
- assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
+ java.util.Date d = new java.util.Date();
+ assertTrue(c.awaitUntil(new java.util.Date(d.getTime() + 2 * LONG_DELAY_MS)));
break;
default:
throw new AssertionError();
@@ -243,7 +241,7 @@
}
for (int i = SIZE; i > 0; i--) {
lock.writeLock().unlock();
- assertEquals(i - 1,lock.getWriteHoldCount());
+ assertEquals(i-1,lock.getWriteHoldCount());
}
}
@@ -260,7 +258,7 @@
}
for (int i = SIZE; i > 0; i--) {
lock.writeLock().unlock();
- assertEquals(i - 1,lock.writeLock().getHoldCount());
+ assertEquals(i-1,lock.writeLock().getHoldCount());
}
}
@@ -277,7 +275,7 @@
}
for (int i = SIZE; i > 0; i--) {
lock.readLock().unlock();
- assertEquals(i - 1,lock.getReadHoldCount());
+ assertEquals(i-1,lock.getReadHoldCount());
}
}
@@ -974,11 +972,11 @@
new ReentrantReadWriteLock(fair);
final Condition c = lock.writeLock().newCondition();
lock.writeLock().lock();
- // We shouldn't assume that nanoTime and currentTimeMillis
- // use the same time source, so don't use nanoTime here.
- java.util.Date delayedDate = delayedDate(timeoutMillis());
- assertFalse(c.awaitUntil(delayedDate));
- assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ java.util.Date d = new java.util.Date();
+ assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
lock.writeLock().unlock();
} catch (InterruptedException fail) { threadUnexpectedException(fail); }
}
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
index 194dd58..a93feea 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -7,15 +7,11 @@
package jsr166;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
@@ -31,9 +27,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -46,7 +40,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ScheduledExecutorSubclassTest.class);
+ // return new TestSuite(...);
// }
static class CustomTask<V> implements RunnableScheduledFuture<V> {
@@ -107,13 +101,17 @@
* execute successfully executes a runnable
*/
public void testExecute() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch done = new CountDownLatch(1);
- final Runnable task = new CheckedRunnable() {
- public void realRun() { done.countDown(); }};
+ CustomExecutor p = new CustomExecutor(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
p.execute(task);
- await(done);
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -121,10 +119,10 @@
* delayed schedule of callable successfully executes after delay
*/
public void testSchedule1() throws Exception {
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
final CountDownLatch done = new CountDownLatch(1);
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final long startTime = System.nanoTime();
+ try {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() {
done.countDown();
@@ -134,6 +132,9 @@
Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
assertSame(Boolean.TRUE, f.get());
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ assertTrue(done.await(0L, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -141,10 +142,10 @@
* delayed schedule of runnable successfully executes after delay
*/
public void testSchedule3() throws Exception {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -154,6 +155,8 @@
await(done);
assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
}
}
@@ -161,10 +164,10 @@
* scheduleAtFixedRate executes runnable after given initial delay
*/
public void testSchedule4() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -176,6 +179,8 @@
await(done);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
f.cancel(true);
+ } finally {
+ joinPool(p);
}
}
@@ -183,10 +188,10 @@
* scheduleWithFixedDelay executes runnable after given initial delay
*/
public void testSchedule5() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -198,6 +203,8 @@
await(done);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
f.cancel(true);
+ } finally {
+ joinPool(p);
}
}
@@ -207,77 +214,58 @@
}
/**
- * scheduleAtFixedRate executes series of tasks at given rate.
- * Eventually, it must hold that:
- * cycles - 1 <= elapsedMillis/delay < cycles
+ * scheduleAtFixedRate executes series of tasks at given rate
*/
public void testFixedRateSequence() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ CustomExecutor p = new CustomExecutor(1);
+ try {
for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
- final long startTime = System.nanoTime();
- final int cycles = 8;
+ long startTime = System.nanoTime();
+ int cycles = 10;
final CountDownLatch done = new CountDownLatch(cycles);
- final Runnable task = new CheckedRunnable() {
+ Runnable task = new CheckedRunnable() {
public void realRun() { done.countDown(); }};
- final ScheduledFuture periodicTask =
+ ScheduledFuture h =
p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS);
- final int totalDelayMillis = (cycles - 1) * delay;
- await(done, totalDelayMillis + LONG_DELAY_MS);
- periodicTask.cancel(true);
- final long elapsedMillis = millisElapsedSince(startTime);
- assertTrue(elapsedMillis >= totalDelayMillis);
- if (elapsedMillis <= cycles * delay)
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
return;
- // else retry with longer delay
}
- fail("unexpected execution rate");
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
}
}
/**
- * scheduleWithFixedDelay executes series of tasks with given period.
- * Eventually, it must hold that each task starts at least delay and at
- * most 2 * delay after the termination of the previous task.
+ * scheduleWithFixedDelay executes series of tasks with given period
*/
public void testFixedDelaySequence() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ CustomExecutor p = new CustomExecutor(1);
+ try {
for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
- final long startTime = System.nanoTime();
- final AtomicLong previous = new AtomicLong(startTime);
- final AtomicBoolean tryLongerDelay = new AtomicBoolean(false);
- final int cycles = 8;
+ long startTime = System.nanoTime();
+ int cycles = 10;
final CountDownLatch done = new CountDownLatch(cycles);
- final int d = delay;
- final Runnable task = new CheckedRunnable() {
- public void realRun() {
- long now = System.nanoTime();
- long elapsedMillis
- = NANOSECONDS.toMillis(now - previous.get());
- if (done.getCount() == cycles) { // first execution
- if (elapsedMillis >= d)
- tryLongerDelay.set(true);
- } else {
- assertTrue(elapsedMillis >= d);
- if (elapsedMillis >= 2 * d)
- tryLongerDelay.set(true);
- }
- previous.set(now);
- done.countDown();
- }};
- final ScheduledFuture periodicTask =
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS);
- final int totalDelayMillis = (cycles - 1) * delay;
- await(done, totalDelayMillis + cycles * LONG_DELAY_MS);
- periodicTask.cancel(true);
- final long elapsedMillis = millisElapsedSince(startTime);
- assertTrue(elapsedMillis >= totalDelayMillis);
- if (!tryLongerDelay.get())
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
return;
- // else retry with longer delay
}
- fail("unexpected execution rate");
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
}
}
@@ -285,107 +273,106 @@
* execute(null) throws NPE
*/
public void testExecuteNull() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
}
/**
* schedule(null) throws NPE
*/
public void testScheduleNull() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- TrackedCallable callable = null;
- Future f = p.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ TrackedCallable callable = null;
+ Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
}
/**
* execute throws RejectedExecutionException if shutdown
*/
public void testSchedule1_RejectedExecutionException() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+
+ joinPool(se);
}
/**
* schedule throws RejectedExecutionException if shutdown
*/
public void testSchedule2_RejectedExecutionException() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpCallable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* schedule callable throws RejectedExecutionException if shutdown
*/
public void testSchedule3_RejectedExecutionException() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpCallable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* scheduleAtFixedRate throws RejectedExecutionException if shutdown
*/
public void testScheduleAtFixedRate1_RejectedExecutionException() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.scheduleAtFixedRate(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleAtFixedRate(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* scheduleWithFixedDelay throws RejectedExecutionException if shutdown
*/
public void testScheduleWithFixedDelay1_RejectedExecutionException() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.scheduleWithFixedDelay(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleWithFixedDelay(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
@@ -393,19 +380,22 @@
* thread becomes active
*/
public void testGetActiveCount() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getActiveCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getActiveCount());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -415,10 +405,10 @@
*/
public void testGetCompletedTaskCount() throws InterruptedException {
final ThreadPoolExecutor p = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch threadProceed = new CountDownLatch(1);
- final CountDownLatch threadDone = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
@@ -437,6 +427,8 @@
fail("timed out");
Thread.yield();
}
+ } finally {
+ joinPool(p);
}
}
@@ -444,10 +436,9 @@
* getCorePoolSize returns size given in constructor if not otherwise set
*/
public void testGetCorePoolSize() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getCorePoolSize());
- }
+ CustomExecutor p = new CustomExecutor(1);
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
}
/**
@@ -456,22 +447,25 @@
*/
public void testGetLargestPoolSize() throws InterruptedException {
final int THREADS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(THREADS);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getLargestPoolSize());
for (int i = 0; i < THREADS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadsStarted.countDown();
- await(done);
+ done.await();
assertEquals(THREADS, p.getLargestPoolSize());
}});
- await(threadsStarted);
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
assertEquals(THREADS, p.getLargestPoolSize());
}
- assertEquals(THREADS, p.getLargestPoolSize());
}
/**
@@ -479,19 +473,22 @@
* become active
*/
public void testGetPoolSize() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getPoolSize());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getPoolSize());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -500,70 +497,58 @@
* submitted
*/
public void testGetTaskCount() throws InterruptedException {
- final int TASKS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final int TASKS = 5;
+ try {
assertEquals(0, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- p.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadStarted.countDown();
- await(done);
- }});
- await(threadStarted);
- assertEquals(1, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- for (int i = 0; i < TASKS; i++) {
- assertEquals(1 + i, p.getTaskCount());
+ for (int i = 0; i < TASKS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- assertEquals(1 + TASKS, p.getTaskCount());
- await(done);
+ done.await();
}});
- }
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(TASKS, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(1 + TASKS, p.getCompletedTaskCount());
}
/**
* getThreadFactory returns factory in constructor if not set
*/
public void testGetThreadFactory() {
- final ThreadFactory threadFactory = new SimpleThreadFactory();
- final CustomExecutor p = new CustomExecutor(1, threadFactory);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ CustomExecutor p = new CustomExecutor(1, tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory sets the thread factory returned by getThreadFactory
*/
public void testSetThreadFactory() {
- final ThreadFactory threadFactory = new SimpleThreadFactory();
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- p.setThreadFactory(threadFactory);
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ CustomExecutor p = new CustomExecutor(1);
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory(null) throws NPE
*/
public void testSetThreadFactoryNull() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setThreadFactory(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ CustomExecutor p = new CustomExecutor(1);
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -571,84 +556,91 @@
* isShutdown is false before shutdown, true after
*/
public void testIsShutdown() {
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ CustomExecutor p = new CustomExecutor(1);
+ try {
assertFalse(p.isShutdown());
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.isShutdown());
}
+ finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.isShutdown());
}
/**
* isTerminated is false before termination, true after
*/
public void testIsTerminated() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminated());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
- assertFalse(p.isTerminated());
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
}
/**
* isTerminating is not true when running or when terminated
*/
public void testIsTerminating() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertFalse(p.isTerminating());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminating());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
}
/**
* getQueue returns the work queue, which contains queued tasks
*/
public void testGetQueue() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(1);
- final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
ScheduledFuture[] tasks = new ScheduledFuture[5];
for (int i = 0; i < tasks.length; i++) {
Runnable r = new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
}};
tasks[i] = p.schedule(r, 1, MILLISECONDS);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
BlockingQueue<Runnable> q = p.getQueue();
assertTrue(q.contains(tasks[tasks.length - 1]));
assertFalse(q.contains(tasks[0]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -656,20 +648,20 @@
* remove(task) removes queued task, and fails to remove active task
*/
public void testRemove() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- ScheduledFuture[] tasks = new ScheduledFuture[5];
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
for (int i = 0; i < tasks.length; i++) {
Runnable r = new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
}};
tasks[i] = p.schedule(r, 1, MILLISECONDS);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
BlockingQueue<Runnable> q = p.getQueue();
assertFalse(p.remove((Runnable)tasks[0]));
assertTrue(q.contains((Runnable)tasks[4]));
@@ -680,6 +672,9 @@
assertTrue(q.contains((Runnable)tasks[3]));
assertTrue(p.remove((Runnable)tasks[3]));
assertFalse(q.contains((Runnable)tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -687,15 +682,12 @@
* purge removes cancelled tasks from the queue
*/
public void testPurge() throws InterruptedException {
- final ScheduledFuture[] tasks = new ScheduledFuture[5];
- final Runnable releaser = new Runnable() { public void run() {
- for (ScheduledFuture task : tasks)
- if (task != null) task.cancel(true); }};
- final CustomExecutor p = new CustomExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, releaser)) {
- for (int i = 0; i < tasks.length; i++)
- tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
- LONG_DELAY_MS, MILLISECONDS);
+ CustomExecutor p = new CustomExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
int max = tasks.length;
if (tasks[4].cancel(true)) --max;
if (tasks[3].cancel(true)) --max;
@@ -707,185 +699,159 @@
long count = p.getTaskCount();
if (count == max)
return;
- } while (millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
fail("Purge failed to remove cancelled tasks");
+ } finally {
+ for (ScheduledFuture task : tasks)
+ task.cancel(true);
+ joinPool(p);
}
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * shutdownNow returns a list containing tasks that were not run
*/
- public void testShutdownNow() throws InterruptedException {
- final int poolSize = 2;
- final int count = 5;
- final AtomicInteger ran = new AtomicInteger(0);
- final CustomExecutor p = new CustomExecutor(poolSize);
- final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
- Runnable waiter = new CheckedRunnable() { public void realRun() {
- threadsStarted.countDown();
- try {
- MILLISECONDS.sleep(2 * LONG_DELAY_MS);
- } catch (InterruptedException success) {}
- ran.getAndIncrement();
- }};
- for (int i = 0; i < count; i++)
- p.execute(waiter);
- await(threadsStarted);
- assertEquals(poolSize, p.getActiveCount());
- assertEquals(0, p.getCompletedTaskCount());
- final List<Runnable> queuedTasks;
+ public void testShutdownNow() {
+ CustomExecutor p = new CustomExecutor(1);
+ for (int i = 0; i < 5; i++)
+ p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
try {
- queuedTasks = p.shutdownNow();
+ List<Runnable> l = p.shutdownNow();
+ assertTrue(p.isShutdown());
+ assertEquals(5, l.size());
} catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
+ // Allowed in case test doesn't have privs
+ } finally {
+ joinPool(p);
}
- assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- assertEquals(count - poolSize, queuedTasks.size());
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertEquals(poolSize, ran.get());
- assertEquals(poolSize, p.getCompletedTaskCount());
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * In default setting, shutdown cancels periodic but not delayed
+ * tasks at shutdown
*/
- public void testShutdownNow_delayedTasks() throws InterruptedException {
- final CustomExecutor p = new CustomExecutor(1);
- List<ScheduledFuture> tasks = new ArrayList<>();
- for (int i = 0; i < 3; i++) {
- Runnable r = new NoOpRunnable();
- tasks.add(p.schedule(r, 9, SECONDS));
- tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS));
- tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS));
- }
- if (testImplementationDetails)
- assertEquals(new HashSet(tasks), new HashSet(p.getQueue()));
- final List<Runnable> queuedTasks;
- try {
- queuedTasks = p.shutdownNow();
- } catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
- }
- assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- if (testImplementationDetails)
- assertEquals(new HashSet(tasks), new HashSet(queuedTasks));
- assertEquals(tasks.size(), queuedTasks.size());
+ public void testShutdown1() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ BlockingQueue<Runnable> q = p.getQueue();
for (ScheduledFuture task : tasks) {
- assertFalse(((CustomTask)task).ran);
assertFalse(task.isDone());
assertFalse(task.isCancelled());
+ assertTrue(q.contains(task));
}
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isShutdown());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertFalse(task.isCancelled());
+ }
}
/**
- * By default, periodic tasks are cancelled at shutdown.
- * By default, delayed tasks keep running after shutdown.
- * Check that changing the default values work:
- * - setExecuteExistingDelayedTasksAfterShutdownPolicy
- * - setContinueExistingPeriodicTasksAfterShutdownPolicy
+ * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
+ * delayed tasks are cancelled at shutdown
*/
- public void testShutdown_cancellation() throws Exception {
- Boolean[] allBooleans = { null, Boolean.FALSE, Boolean.TRUE };
- for (Boolean policy : allBooleans)
- {
- final int poolSize = 2;
- final CustomExecutor p = new CustomExecutor(poolSize);
- final boolean effectiveDelayedPolicy = (policy != Boolean.FALSE);
- final boolean effectivePeriodicPolicy = (policy == Boolean.TRUE);
- final boolean effectiveRemovePolicy = (policy == Boolean.TRUE);
- if (policy != null) {
- p.setExecuteExistingDelayedTasksAfterShutdownPolicy(policy);
- p.setContinueExistingPeriodicTasksAfterShutdownPolicy(policy);
- p.setRemoveOnCancelPolicy(policy);
- }
- assertEquals(effectiveDelayedPolicy,
- p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
- assertEquals(effectivePeriodicPolicy,
- p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
- assertEquals(effectiveRemovePolicy,
- p.getRemoveOnCancelPolicy());
- // Strategy: Wedge the pool with poolSize "blocker" threads
- final AtomicInteger ran = new AtomicInteger(0);
- final CountDownLatch poolBlocked = new CountDownLatch(poolSize);
- final CountDownLatch unblock = new CountDownLatch(1);
- final CountDownLatch periodicLatch1 = new CountDownLatch(2);
- final CountDownLatch periodicLatch2 = new CountDownLatch(2);
- Runnable task = new CheckedRunnable() { public void realRun()
- throws InterruptedException {
- poolBlocked.countDown();
- assertTrue(unblock.await(LONG_DELAY_MS, MILLISECONDS));
- ran.getAndIncrement();
- }};
- List<Future<?>> blockers = new ArrayList<>();
- List<Future<?>> periodics = new ArrayList<>();
- List<Future<?>> delayeds = new ArrayList<>();
- for (int i = 0; i < poolSize; i++)
- blockers.add(p.submit(task));
- assertTrue(poolBlocked.await(LONG_DELAY_MS, MILLISECONDS));
-
- periodics.add(p.scheduleAtFixedRate(countDowner(periodicLatch1),
- 1, 1, MILLISECONDS));
- periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
- 1, 1, MILLISECONDS));
- delayeds.add(p.schedule(task, 1, MILLISECONDS));
-
- assertTrue(p.getQueue().containsAll(periodics));
- assertTrue(p.getQueue().containsAll(delayeds));
+ public void testShutdown2() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ p.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ assertFalse(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ BlockingQueue q = p.getQueue();
+ assertEquals(tasks.length, q.size());
try { p.shutdown(); } catch (SecurityException ok) { return; }
assertTrue(p.isShutdown());
- assertFalse(p.isTerminated());
- for (Future<?> periodic : periodics) {
- assertTrue(effectivePeriodicPolicy ^ periodic.isCancelled());
- assertTrue(effectivePeriodicPolicy ^ periodic.isDone());
- }
- for (Future<?> delayed : delayeds) {
- assertTrue(effectiveDelayedPolicy ^ delayed.isCancelled());
- assertTrue(effectiveDelayedPolicy ^ delayed.isDone());
- }
- if (testImplementationDetails) {
- assertEquals(effectivePeriodicPolicy,
- p.getQueue().containsAll(periodics));
- assertEquals(effectiveDelayedPolicy,
- p.getQueue().containsAll(delayeds));
- }
- // Release all pool threads
- unblock.countDown();
-
- for (Future<?> delayed : delayeds) {
- if (effectiveDelayedPolicy) {
- assertNull(delayed.get());
- }
- }
- if (effectivePeriodicPolicy) {
- assertTrue(periodicLatch1.await(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(periodicLatch2.await(LONG_DELAY_MS, MILLISECONDS));
- for (Future<?> periodic : periodics) {
- assertTrue(periodic.cancel(false));
- assertTrue(periodic.isCancelled());
- assertTrue(periodic.isDone());
- }
- }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(q.isEmpty());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
assertTrue(p.isTerminated());
- assertEquals(2 + (effectiveDelayedPolicy ? 1 : 0), ran.get());
- }}
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
+ * periodic tasks are cancelled at shutdown
+ */
+ public void testShutdown3() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ long initialDelay = LONG_DELAY_MS;
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(new NoOpRunnable(), initialDelay,
+ 5, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(p.getQueue().isEmpty());
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ joinPool(p);
+ }
+
+ /**
+ * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
+ * periodic tasks are not cancelled at shutdown
+ */
+ public void testShutdown4() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ final CountDownLatch counter = new CountDownLatch(2);
+ try {
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertTrue(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ final Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ counter.countDown();
+ }};
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(r, 1, 1, MILLISECONDS);
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertFalse(task.isCancelled());
+ assertFalse(p.isTerminated());
+ assertTrue(p.isShutdown());
+ assertTrue(counter.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(task.isCancelled());
+ assertTrue(task.cancel(false));
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+ finally {
+ joinPool(p);
+ }
+ }
/**
* completed submit of callable returns result
*/
public void testSubmitCallable() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
Future<String> future = e.submit(new StringTask());
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -893,11 +859,13 @@
* completed submit of runnable returns successfully
*/
public void testSubmitRunnable() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
Future<?> future = e.submit(new NoOpRunnable());
future.get();
assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -905,11 +873,13 @@
* completed submit of (runnable, result) returns result
*/
public void testSubmitRunnable2() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -917,12 +887,13 @@
* invokeAny(null) throws NPE
*/
public void testInvokeAny1() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -930,12 +901,13 @@
* invokeAny(empty collection) throws IAE
*/
public void testInvokeAny2() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -943,17 +915,18 @@
* invokeAny(c) throws NPE if c has null elements
*/
public void testInvokeAny3() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -961,16 +934,16 @@
* invokeAny(c) throws ExecutionException if no task completes
*/
public void testInvokeAny4() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -978,13 +951,15 @@
* invokeAny(c) returns result of some task
*/
public void testInvokeAny5() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -992,12 +967,13 @@
* invokeAll(null) throws NPE
*/
public void testInvokeAll1() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1005,10 +981,12 @@
* invokeAll(empty collection) returns empty collection
*/
public void testInvokeAll2() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1016,15 +994,16 @@
* invokeAll(c) throws NPE if c has null elements
*/
public void testInvokeAll3() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1032,18 +1011,18 @@
* get of invokeAll(c) throws exception on failed task
*/
public void testInvokeAll4() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures = e.invokeAll(l);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1051,8 +1030,8 @@
* invokeAll(c) returns results of all completed tasks
*/
public void testInvokeAll5() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -1060,6 +1039,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1067,12 +1048,13 @@
* timed invokeAny(null) throws NPE
*/
public void testTimedInvokeAny1() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1080,14 +1062,15 @@
* timed invokeAny(,,null) throws NPE
*/
public void testTimedInvokeAnyNullTimeUnit() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1095,12 +1078,13 @@
* timed invokeAny(empty collection) throws IAE
*/
public void testTimedInvokeAny2() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1109,16 +1093,17 @@
*/
public void testTimedInvokeAny3() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1126,18 +1111,16 @@
* timed invokeAny(c) throws ExecutionException if no task completes
*/
public void testTimedInvokeAny4() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1145,15 +1128,15 @@
* timed invokeAny(c) returns result of some task
*/
public void testTimedInvokeAny5() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -1161,12 +1144,13 @@
* timed invokeAll(null) throws NPE
*/
public void testTimedInvokeAll1() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1174,14 +1158,15 @@
* timed invokeAll(,,null) throws NPE
*/
public void testTimedInvokeAllNullTimeUnit() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1189,10 +1174,12 @@
* timed invokeAll(empty collection) returns empty collection
*/
public void testTimedInvokeAll2() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1200,15 +1187,16 @@
* timed invokeAll(c) throws NPE if c has null elements
*/
public void testTimedInvokeAll3() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1216,19 +1204,19 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testTimedInvokeAll4() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures =
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1236,16 +1224,18 @@
* timed invokeAll(c) returns results of all completed tasks
*/
public void testTimedInvokeAll5() throws Exception {
- final ExecutorService e = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1253,37 +1243,21 @@
* timed invokeAll(c) cancels tasks not completed by timeout
*/
public void testTimedInvokeAll6() throws Exception {
- for (long timeout = timeoutMillis();;) {
- final CountDownLatch done = new CountDownLatch(1);
- final Callable<String> waiter = new CheckedCallable<String>() {
- public String realCall() {
- try { done.await(LONG_DELAY_MS, MILLISECONDS); }
- catch (InterruptedException ok) {}
- return "1"; }};
- final ExecutorService p = new CustomExecutor(2);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- List<Callable<String>> tasks = new ArrayList<>();
- tasks.add(new StringTask("0"));
- tasks.add(waiter);
- tasks.add(new StringTask("2"));
- long startTime = System.nanoTime();
- List<Future<String>> futures =
- p.invokeAll(tasks, timeout, MILLISECONDS);
- assertEquals(tasks.size(), futures.size());
- assertTrue(millisElapsedSince(startTime) >= timeout);
- for (Future future : futures)
- assertTrue(future.isDone());
- assertTrue(futures.get(1).isCancelled());
- try {
- assertEquals("0", futures.get(0).get());
- assertEquals("2", futures.get(2).get());
- break;
- } catch (CancellationException retryWithLongerTimeout) {
- timeout *= 2;
- if (timeout >= LONG_DELAY_MS / 2)
- fail("expected exactly one task to be cancelled");
- }
- }
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
index 81f7370..a2e83d0 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -9,15 +9,11 @@
package jsr166;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -28,9 +24,7 @@
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -43,20 +37,24 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ScheduledExecutorTest.class);
+ // return new TestSuite(...);
// }
/**
* execute successfully executes a runnable
*/
public void testExecute() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch done = new CountDownLatch(1);
- final Runnable task = new CheckedRunnable() {
- public void realRun() { done.countDown(); }};
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
p.execute(task);
- assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -64,10 +62,10 @@
* delayed schedule of callable successfully executes after delay
*/
public void testSchedule1() throws Exception {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() {
done.countDown();
@@ -78,6 +76,8 @@
assertSame(Boolean.TRUE, f.get());
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
assertTrue(done.await(0L, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -85,10 +85,10 @@
* delayed schedule of runnable successfully executes after delay
*/
public void testSchedule3() throws Exception {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -98,6 +98,8 @@
await(done);
assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
}
}
@@ -105,10 +107,10 @@
* scheduleAtFixedRate executes runnable after given initial delay
*/
public void testSchedule4() throws Exception {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -120,6 +122,8 @@
await(done);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
f.cancel(true);
+ } finally {
+ joinPool(p);
}
}
@@ -127,10 +131,10 @@
* scheduleWithFixedDelay executes runnable after given initial delay
*/
public void testSchedule5() throws Exception {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final long startTime = System.nanoTime();
- final CountDownLatch done = new CountDownLatch(1);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() {
done.countDown();
@@ -142,6 +146,8 @@
await(done);
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
f.cancel(true);
+ } finally {
+ joinPool(p);
}
}
@@ -151,77 +157,58 @@
}
/**
- * scheduleAtFixedRate executes series of tasks at given rate.
- * Eventually, it must hold that:
- * cycles - 1 <= elapsedMillis/delay < cycles
+ * scheduleAtFixedRate executes series of tasks at given rate
*/
public void testFixedRateSequence() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ try {
for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
- final long startTime = System.nanoTime();
- final int cycles = 8;
+ long startTime = System.nanoTime();
+ int cycles = 10;
final CountDownLatch done = new CountDownLatch(cycles);
- final Runnable task = new CheckedRunnable() {
+ Runnable task = new CheckedRunnable() {
public void realRun() { done.countDown(); }};
- final ScheduledFuture periodicTask =
+ ScheduledFuture h =
p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS);
- final int totalDelayMillis = (cycles - 1) * delay;
- await(done, totalDelayMillis + LONG_DELAY_MS);
- periodicTask.cancel(true);
- final long elapsedMillis = millisElapsedSince(startTime);
- assertTrue(elapsedMillis >= totalDelayMillis);
- if (elapsedMillis <= cycles * delay)
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
return;
- // else retry with longer delay
}
- fail("unexpected execution rate");
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
}
}
/**
- * scheduleWithFixedDelay executes series of tasks with given period.
- * Eventually, it must hold that each task starts at least delay and at
- * most 2 * delay after the termination of the previous task.
+ * scheduleWithFixedDelay executes series of tasks with given period
*/
public void testFixedDelaySequence() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ try {
for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
- final long startTime = System.nanoTime();
- final AtomicLong previous = new AtomicLong(startTime);
- final AtomicBoolean tryLongerDelay = new AtomicBoolean(false);
- final int cycles = 8;
+ long startTime = System.nanoTime();
+ int cycles = 10;
final CountDownLatch done = new CountDownLatch(cycles);
- final int d = delay;
- final Runnable task = new CheckedRunnable() {
- public void realRun() {
- long now = System.nanoTime();
- long elapsedMillis
- = NANOSECONDS.toMillis(now - previous.get());
- if (done.getCount() == cycles) { // first execution
- if (elapsedMillis >= d)
- tryLongerDelay.set(true);
- } else {
- assertTrue(elapsedMillis >= d);
- if (elapsedMillis >= 2 * d)
- tryLongerDelay.set(true);
- }
- previous.set(now);
- done.countDown();
- }};
- final ScheduledFuture periodicTask =
+ Runnable task = new CheckedRunnable() {
+ public void realRun() { done.countDown(); }};
+ ScheduledFuture h =
p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS);
- final int totalDelayMillis = (cycles - 1) * delay;
- await(done, totalDelayMillis + cycles * LONG_DELAY_MS);
- periodicTask.cancel(true);
- final long elapsedMillis = millisElapsedSince(startTime);
- assertTrue(elapsedMillis >= totalDelayMillis);
- if (!tryLongerDelay.get())
+ done.await();
+ h.cancel(true);
+ double normalizedTime =
+ (double) millisElapsedSince(startTime) / delay;
+ if (normalizedTime >= cycles - 1 &&
+ normalizedTime <= cycles)
return;
- // else retry with longer delay
}
- fail("unexpected execution rate");
+ throw new AssertionError("unexpected execution rate");
+ } finally {
+ joinPool(p);
}
}
@@ -229,107 +216,108 @@
* execute(null) throws NPE
*/
public void testExecuteNull() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ ScheduledThreadPoolExecutor se = null;
+ try {
+ se = new ScheduledThreadPoolExecutor(1);
+ se.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(se);
}
/**
* schedule(null) throws NPE
*/
public void testScheduleNull() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- TrackedCallable callable = null;
- Future f = p.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ TrackedCallable callable = null;
+ Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
}
/**
* execute throws RejectedExecutionException if shutdown
*/
public void testSchedule1_RejectedExecutionException() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+
+ joinPool(se);
}
/**
* schedule throws RejectedExecutionException if shutdown
*/
public void testSchedule2_RejectedExecutionException() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpCallable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* schedule callable throws RejectedExecutionException if shutdown
*/
public void testSchedule3_RejectedExecutionException() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.schedule(new NoOpCallable(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* scheduleAtFixedRate throws RejectedExecutionException if shutdown
*/
public void testScheduleAtFixedRate1_RejectedExecutionException() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.scheduleAtFixedRate(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleAtFixedRate(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
* scheduleWithFixedDelay throws RejectedExecutionException if shutdown
*/
public void testScheduleWithFixedDelay1_RejectedExecutionException() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.shutdown();
- p.scheduleWithFixedDelay(new NoOpRunnable(),
- MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (RejectedExecutionException success) {
- } catch (SecurityException ok) {}
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleWithFixedDelay(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
}
+ joinPool(se);
}
/**
@@ -337,19 +325,22 @@
* thread becomes active
*/
public void testGetActiveCount() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getActiveCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getActiveCount());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -359,10 +350,10 @@
*/
public void testGetCompletedTaskCount() throws InterruptedException {
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch threadProceed = new CountDownLatch(1);
- final CountDownLatch threadDone = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
@@ -381,6 +372,8 @@
fail("timed out");
Thread.yield();
}
+ } finally {
+ joinPool(p);
}
}
@@ -389,9 +382,8 @@
*/
public void testGetCorePoolSize() throws InterruptedException {
ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getCorePoolSize());
- }
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
}
/**
@@ -403,19 +395,22 @@
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(THREADS);
final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
final CountDownLatch done = new CountDownLatch(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ try {
assertEquals(0, p.getLargestPoolSize());
for (int i = 0; i < THREADS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadsStarted.countDown();
- await(done);
+ done.await();
assertEquals(THREADS, p.getLargestPoolSize());
}});
- await(threadsStarted);
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
assertEquals(THREADS, p.getLargestPoolSize());
}
- assertEquals(THREADS, p.getLargestPoolSize());
}
/**
@@ -426,16 +421,19 @@
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
final CountDownLatch threadStarted = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ try {
assertEquals(0, p.getPoolSize());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getPoolSize());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -444,71 +442,58 @@
* submitted
*/
public void testGetTaskCount() throws InterruptedException {
- final int TASKS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final int TASKS = 5;
+ try {
assertEquals(0, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- p.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadStarted.countDown();
- await(done);
- }});
- await(threadStarted);
- assertEquals(1, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- for (int i = 0; i < TASKS; i++) {
- assertEquals(1 + i, p.getTaskCount());
+ for (int i = 0; i < TASKS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- assertEquals(1 + TASKS, p.getTaskCount());
- await(done);
+ done.await();
}});
- }
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(TASKS, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(1 + TASKS, p.getCompletedTaskCount());
}
/**
* getThreadFactory returns factory in constructor if not set
*/
public void testGetThreadFactory() throws InterruptedException {
- final ThreadFactory threadFactory = new SimpleThreadFactory();
- final ScheduledThreadPoolExecutor p =
- new ScheduledThreadPoolExecutor(1, threadFactory);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1, tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory sets the thread factory returned by getThreadFactory
*/
public void testSetThreadFactory() throws InterruptedException {
- ThreadFactory threadFactory = new SimpleThreadFactory();
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- p.setThreadFactory(threadFactory);
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory(null) throws NPE
*/
public void testSetThreadFactoryNull() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setThreadFactory(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -517,7 +502,7 @@
*/
public void testIsShutdown() {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
try {
assertFalse(p.isShutdown());
}
@@ -532,23 +517,24 @@
*/
public void testIsTerminated() throws InterruptedException {
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
- assertFalse(p.isTerminated());
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminated());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
}
/**
@@ -558,45 +544,49 @@
final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
final CountDownLatch threadStarted = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(1);
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
assertFalse(p.isTerminating());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminating());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
}
/**
* getQueue returns the work queue, which contains queued tasks
*/
public void testGetQueue() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(1);
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
ScheduledFuture[] tasks = new ScheduledFuture[5];
for (int i = 0; i < tasks.length; i++) {
Runnable r = new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
}};
tasks[i] = p.schedule(r, 1, MILLISECONDS);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
BlockingQueue<Runnable> q = p.getQueue();
assertTrue(q.contains(tasks[tasks.length - 1]));
assertFalse(q.contains(tasks[0]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -604,20 +594,20 @@
* remove(task) removes queued task, and fails to remove active task
*/
public void testRemove() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- ScheduledFuture[] tasks = new ScheduledFuture[5];
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
for (int i = 0; i < tasks.length; i++) {
Runnable r = new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
}};
tasks[i] = p.schedule(r, 1, MILLISECONDS);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
BlockingQueue<Runnable> q = p.getQueue();
assertFalse(p.remove((Runnable)tasks[0]));
assertTrue(q.contains((Runnable)tasks[4]));
@@ -628,6 +618,9 @@
assertTrue(q.contains((Runnable)tasks[3]));
assertTrue(p.remove((Runnable)tasks[3]));
assertFalse(q.contains((Runnable)tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -635,15 +628,12 @@
* purge eventually removes cancelled tasks from the queue
*/
public void testPurge() throws InterruptedException {
- final ScheduledFuture[] tasks = new ScheduledFuture[5];
- final Runnable releaser = new Runnable() { public void run() {
- for (ScheduledFuture task : tasks)
- if (task != null) task.cancel(true); }};
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p, releaser)) {
- for (int i = 0; i < tasks.length; i++)
- tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
- LONG_DELAY_MS, MILLISECONDS);
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
int max = tasks.length;
if (tasks[4].cancel(true)) --max;
if (tasks[3].cancel(true)) --max;
@@ -655,186 +645,159 @@
long count = p.getTaskCount();
if (count == max)
return;
- } while (millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
fail("Purge failed to remove cancelled tasks");
+ } finally {
+ for (ScheduledFuture task : tasks)
+ task.cancel(true);
+ joinPool(p);
}
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * shutdownNow returns a list containing tasks that were not run
*/
- public void testShutdownNow() throws InterruptedException {
- final int poolSize = 2;
- final int count = 5;
- final AtomicInteger ran = new AtomicInteger(0);
- final ScheduledThreadPoolExecutor p =
- new ScheduledThreadPoolExecutor(poolSize);
- final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
- Runnable waiter = new CheckedRunnable() { public void realRun() {
- threadsStarted.countDown();
- try {
- MILLISECONDS.sleep(2 * LONG_DELAY_MS);
- } catch (InterruptedException success) {}
- ran.getAndIncrement();
- }};
- for (int i = 0; i < count; i++)
- p.execute(waiter);
- await(threadsStarted);
- assertEquals(poolSize, p.getActiveCount());
- assertEquals(0, p.getCompletedTaskCount());
- final List<Runnable> queuedTasks;
+ public void testShutdownNow() {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ for (int i = 0; i < 5; i++)
+ p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
try {
- queuedTasks = p.shutdownNow();
+ List<Runnable> l = p.shutdownNow();
+ assertTrue(p.isShutdown());
+ assertEquals(5, l.size());
} catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
+ // Allowed in case test doesn't have privs
+ } finally {
+ joinPool(p);
}
- assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- assertEquals(count - poolSize, queuedTasks.size());
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertEquals(poolSize, ran.get());
- assertEquals(poolSize, p.getCompletedTaskCount());
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * In default setting, shutdown cancels periodic but not delayed
+ * tasks at shutdown
*/
- public void testShutdownNow_delayedTasks() throws InterruptedException {
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- List<ScheduledFuture> tasks = new ArrayList<>();
- for (int i = 0; i < 3; i++) {
- Runnable r = new NoOpRunnable();
- tasks.add(p.schedule(r, 9, SECONDS));
- tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS));
- tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS));
- }
- if (testImplementationDetails)
- assertEquals(new HashSet(tasks), new HashSet(p.getQueue()));
- final List<Runnable> queuedTasks;
- try {
- queuedTasks = p.shutdownNow();
- } catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
- }
- assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- if (testImplementationDetails)
- assertEquals(new HashSet(tasks), new HashSet(queuedTasks));
- assertEquals(tasks.size(), queuedTasks.size());
+ public void testShutdown1() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ BlockingQueue<Runnable> q = p.getQueue();
for (ScheduledFuture task : tasks) {
assertFalse(task.isDone());
assertFalse(task.isCancelled());
+ assertTrue(q.contains(task));
}
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isShutdown());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertFalse(task.isCancelled());
+ }
}
/**
- * By default, periodic tasks are cancelled at shutdown.
- * By default, delayed tasks keep running after shutdown.
- * Check that changing the default values work:
- * - setExecuteExistingDelayedTasksAfterShutdownPolicy
- * - setContinueExistingPeriodicTasksAfterShutdownPolicy
+ * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
+ * delayed tasks are cancelled at shutdown
*/
- public void testShutdown_cancellation() throws Exception {
- Boolean[] allBooleans = { null, Boolean.FALSE, Boolean.TRUE };
- for (Boolean policy : allBooleans)
- {
- final int poolSize = 2;
- final ScheduledThreadPoolExecutor p
- = new ScheduledThreadPoolExecutor(poolSize);
- final boolean effectiveDelayedPolicy = (policy != Boolean.FALSE);
- final boolean effectivePeriodicPolicy = (policy == Boolean.TRUE);
- final boolean effectiveRemovePolicy = (policy == Boolean.TRUE);
- if (policy != null) {
- p.setExecuteExistingDelayedTasksAfterShutdownPolicy(policy);
- p.setContinueExistingPeriodicTasksAfterShutdownPolicy(policy);
- p.setRemoveOnCancelPolicy(policy);
- }
- assertEquals(effectiveDelayedPolicy,
- p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
- assertEquals(effectivePeriodicPolicy,
- p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
- assertEquals(effectiveRemovePolicy,
- p.getRemoveOnCancelPolicy());
- // Strategy: Wedge the pool with poolSize "blocker" threads
- final AtomicInteger ran = new AtomicInteger(0);
- final CountDownLatch poolBlocked = new CountDownLatch(poolSize);
- final CountDownLatch unblock = new CountDownLatch(1);
- final CountDownLatch periodicLatch1 = new CountDownLatch(2);
- final CountDownLatch periodicLatch2 = new CountDownLatch(2);
- Runnable task = new CheckedRunnable() { public void realRun()
- throws InterruptedException {
- poolBlocked.countDown();
- assertTrue(unblock.await(LONG_DELAY_MS, MILLISECONDS));
- ran.getAndIncrement();
- }};
- List<Future<?>> blockers = new ArrayList<>();
- List<Future<?>> periodics = new ArrayList<>();
- List<Future<?>> delayeds = new ArrayList<>();
- for (int i = 0; i < poolSize; i++)
- blockers.add(p.submit(task));
- assertTrue(poolBlocked.await(LONG_DELAY_MS, MILLISECONDS));
-
- periodics.add(p.scheduleAtFixedRate(countDowner(periodicLatch1),
- 1, 1, MILLISECONDS));
- periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
- 1, 1, MILLISECONDS));
- delayeds.add(p.schedule(task, 1, MILLISECONDS));
-
- assertTrue(p.getQueue().containsAll(periodics));
- assertTrue(p.getQueue().containsAll(delayeds));
+ public void testShutdown2() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ p.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ assertFalse(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ BlockingQueue q = p.getQueue();
+ assertEquals(tasks.length, q.size());
try { p.shutdown(); } catch (SecurityException ok) { return; }
assertTrue(p.isShutdown());
- assertFalse(p.isTerminated());
- for (Future<?> periodic : periodics) {
- assertTrue(effectivePeriodicPolicy ^ periodic.isCancelled());
- assertTrue(effectivePeriodicPolicy ^ periodic.isDone());
- }
- for (Future<?> delayed : delayeds) {
- assertTrue(effectiveDelayedPolicy ^ delayed.isCancelled());
- assertTrue(effectiveDelayedPolicy ^ delayed.isDone());
- }
- if (testImplementationDetails) {
- assertEquals(effectivePeriodicPolicy,
- p.getQueue().containsAll(periodics));
- assertEquals(effectiveDelayedPolicy,
- p.getQueue().containsAll(delayeds));
- }
- // Release all pool threads
- unblock.countDown();
-
- for (Future<?> delayed : delayeds) {
- if (effectiveDelayedPolicy) {
- assertNull(delayed.get());
- }
- }
- if (effectivePeriodicPolicy) {
- assertTrue(periodicLatch1.await(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(periodicLatch2.await(LONG_DELAY_MS, MILLISECONDS));
- for (Future<?> periodic : periodics) {
- assertTrue(periodic.cancel(false));
- assertTrue(periodic.isCancelled());
- assertTrue(periodic.isDone());
- }
- }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(q.isEmpty());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
assertTrue(p.isTerminated());
- assertEquals(2 + (effectiveDelayedPolicy ? 1 : 0), ran.get());
- }}
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
+ * periodic tasks are cancelled at shutdown
+ */
+ public void testShutdown3() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ long initialDelay = LONG_DELAY_MS;
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(new NoOpRunnable(), initialDelay,
+ 5, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(p.getQueue().isEmpty());
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ joinPool(p);
+ }
+
+ /**
+ * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
+ * periodic tasks are not cancelled at shutdown
+ */
+ public void testShutdown4() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch counter = new CountDownLatch(2);
+ try {
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertTrue(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ final Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ counter.countDown();
+ }};
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(r, 1, 1, MILLISECONDS);
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertFalse(task.isCancelled());
+ assertFalse(p.isTerminated());
+ assertTrue(p.isShutdown());
+ assertTrue(counter.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(task.isCancelled());
+ assertTrue(task.cancel(false));
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+ finally {
+ joinPool(p);
+ }
+ }
/**
* completed submit of callable returns result
*/
public void testSubmitCallable() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
Future<String> future = e.submit(new StringTask());
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -842,11 +805,13 @@
* completed submit of runnable returns successfully
*/
public void testSubmitRunnable() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
Future<?> future = e.submit(new NoOpRunnable());
future.get();
assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -854,11 +819,13 @@
* completed submit of (runnable, result) returns result
*/
public void testSubmitRunnable2() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -866,12 +833,13 @@
* invokeAny(null) throws NPE
*/
public void testInvokeAny1() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -879,12 +847,13 @@
* invokeAny(empty collection) throws IAE
*/
public void testInvokeAny2() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -893,16 +862,17 @@
*/
public void testInvokeAny3() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -910,16 +880,16 @@
* invokeAny(c) throws ExecutionException if no task completes
*/
public void testInvokeAny4() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -927,13 +897,15 @@
* invokeAny(c) returns result of some task
*/
public void testInvokeAny5() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -941,12 +913,13 @@
* invokeAll(null) throws NPE
*/
public void testInvokeAll1() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -954,10 +927,12 @@
* invokeAll(empty collection) returns empty collection
*/
public void testInvokeAll2() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -965,15 +940,16 @@
* invokeAll(c) throws NPE if c has null elements
*/
public void testInvokeAll3() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -981,18 +957,18 @@
* get of invokeAll(c) throws exception on failed task
*/
public void testInvokeAll4() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures = e.invokeAll(l);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1000,8 +976,8 @@
* invokeAll(c) returns results of all completed tasks
*/
public void testInvokeAll5() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -1009,6 +985,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1016,12 +994,13 @@
* timed invokeAny(null) throws NPE
*/
public void testTimedInvokeAny1() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1029,14 +1008,15 @@
* timed invokeAny(,,null) throws NPE
*/
public void testTimedInvokeAnyNullTimeUnit() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1044,12 +1024,13 @@
* timed invokeAny(empty collection) throws IAE
*/
public void testTimedInvokeAny2() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1058,16 +1039,17 @@
*/
public void testTimedInvokeAny3() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1075,18 +1057,16 @@
* timed invokeAny(c) throws ExecutionException if no task completes
*/
public void testTimedInvokeAny4() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1094,15 +1074,15 @@
* timed invokeAny(c) returns result of some task
*/
public void testTimedInvokeAny5() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -1110,12 +1090,13 @@
* timed invokeAll(null) throws NPE
*/
public void testTimedInvokeAll1() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1123,14 +1104,15 @@
* timed invokeAll(,,null) throws NPE
*/
public void testTimedInvokeAllNullTimeUnit() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1138,11 +1120,12 @@
* timed invokeAll(empty collection) returns empty collection
*/
public void testTimedInvokeAll2() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1150,15 +1133,16 @@
* timed invokeAll(c) throws NPE if c has null elements
*/
public void testTimedInvokeAll3() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1166,19 +1150,19 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testTimedInvokeAll4() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1186,16 +1170,18 @@
* timed invokeAll(c) returns results of all completed tasks
*/
public void testTimedInvokeAll5() throws Exception {
- final ExecutorService e = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1203,60 +1189,21 @@
* timed invokeAll(c) cancels tasks not completed by timeout
*/
public void testTimedInvokeAll6() throws Exception {
- for (long timeout = timeoutMillis();;) {
- final CountDownLatch done = new CountDownLatch(1);
- final Callable<String> waiter = new CheckedCallable<String>() {
- public String realCall() {
- try { done.await(LONG_DELAY_MS, MILLISECONDS); }
- catch (InterruptedException ok) {}
- return "1"; }};
- final ExecutorService p = new ScheduledThreadPoolExecutor(2);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- List<Callable<String>> tasks = new ArrayList<>();
- tasks.add(new StringTask("0"));
- tasks.add(waiter);
- tasks.add(new StringTask("2"));
- long startTime = System.nanoTime();
- List<Future<String>> futures =
- p.invokeAll(tasks, timeout, MILLISECONDS);
- assertEquals(tasks.size(), futures.size());
- assertTrue(millisElapsedSince(startTime) >= timeout);
- for (Future future : futures)
- assertTrue(future.isDone());
- assertTrue(futures.get(1).isCancelled());
- try {
- assertEquals("0", futures.get(0).get());
- assertEquals("2", futures.get(2).get());
- break;
- } catch (CancellationException retryWithLongerTimeout) {
- timeout *= 2;
- if (timeout >= LONG_DELAY_MS / 2)
- fail("expected exactly one task to be cancelled");
- }
- }
- }
- }
-
- /**
- * A fixed delay task with overflowing period should not prevent a
- * one-shot task from executing.
- * https://bugs.openjdk.java.net/browse/JDK-8051859
- */
- public void testScheduleWithFixedDelay_overflow() throws Exception {
- final CountDownLatch delayedDone = new CountDownLatch(1);
- final CountDownLatch immediateDone = new CountDownLatch(1);
- final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
- try (PoolCleaner cleaner = cleaner(p)) {
- final Runnable immediate = new Runnable() { public void run() {
- immediateDone.countDown();
- }};
- final Runnable delayed = new Runnable() { public void run() {
- delayedDone.countDown();
- p.submit(immediate);
- }};
- p.scheduleWithFixedDelay(delayed, 0L, Long.MAX_VALUE, SECONDS);
- await(delayedDone);
- await(immediateDone);
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
index 09c82c8..db4f4b4 100644
--- a/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
@@ -26,9 +26,8 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(SemaphoreTest.class);
+ // return new TestSuite(...);
// }
-
/**
* Subclass to expose protected methods
*/
@@ -472,16 +471,11 @@
clone.release();
assertEquals(2, s.availablePermits());
assertEquals(1, clone.availablePermits());
- assertFalse(s.hasQueuedThreads());
- assertFalse(clone.hasQueuedThreads());
- } catch (InterruptedException e) { threadUnexpectedException(e); }
- {
- PublicSemaphore s = new PublicSemaphore(0, fair);
+ s = new Semaphore(0, fair);
Thread t = newStartedThread(new InterruptibleLockRunnable(s));
- // waitForQueuedThreads(s); // suffers from "flicker", so ...
- waitForQueuedThread(s, t); // ... we use this instead
- PublicSemaphore clone = serialClone(s);
+ waitForQueuedThreads(s);
+ clone = serialClone(s);
assertEquals(fair, s.isFair());
assertEquals(fair, clone.isFair());
assertEquals(0, s.availablePermits());
@@ -492,7 +486,7 @@
awaitTermination(t);
assertFalse(s.hasQueuedThreads());
assertFalse(clone.hasQueuedThreads());
- }
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
}
/**
@@ -600,7 +594,7 @@
s.acquire(3);
}});
- waitForQueuedThread(s, t1);
+ waitForQueuedThreads(s);
Thread t2 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
diff --git a/jsr166-tests/src/test/java/jsr166/StampedLockTest.java b/jsr166-tests/src/test/java/jsr166/StampedLockTest.java
deleted file mode 100644
index d347c7d..0000000
--- a/jsr166-tests/src/test/java/jsr166/StampedLockTest.java
+++ /dev/null
@@ -1,884 +0,0 @@
-/*
- * 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 jsr166;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.StampedLock;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class StampedLockTest extends JSR166TestCase {
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(StampedLockTest.class);
- // }
-
- /**
- * A runnable calling writeLockInterruptibly
- */
- class InterruptibleLockRunnable extends CheckedRunnable {
- final StampedLock lock;
- InterruptibleLockRunnable(StampedLock l) { lock = l; }
- public void realRun() throws InterruptedException {
- lock.writeLockInterruptibly();
- }
- }
-
- /**
- * A runnable calling writeLockInterruptibly that expects to be
- * interrupted
- */
- class InterruptedLockRunnable extends CheckedInterruptedRunnable {
- final StampedLock lock;
- InterruptedLockRunnable(StampedLock l) { lock = l; }
- public void realRun() throws InterruptedException {
- lock.writeLockInterruptibly();
- }
- }
-
- /**
- * Releases write lock, checking isWriteLocked before and after
- */
- void releaseWriteLock(StampedLock lock, long s) {
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
- assertFalse(lock.isWriteLocked());
- }
-
- /**
- * Constructed StampedLock is in unlocked state
- */
- public void testConstructor() {
- StampedLock lock;
- lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
-
- /**
- * write-locking and read-locking an unlocked lock succeed
- */
- public void testLock() {
- StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- lock.unlockWrite(s);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- lock.unlockRead(rs);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
-
- /**
- * unlock releases either a read or write lock
- */
- public void testUnlock() {
- StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- lock.unlock(s);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- lock.unlock(rs);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
-
- /**
- * tryUnlockRead/Write succeeds if locked in associated mode else
- * returns false
- */
- public void testTryUnlock() {
- StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- assertFalse(lock.tryUnlockRead());
- assertTrue(lock.tryUnlockWrite());
- assertFalse(lock.tryUnlockWrite());
- assertFalse(lock.tryUnlockRead());
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- assertFalse(lock.tryUnlockWrite());
- assertTrue(lock.tryUnlockRead());
- assertFalse(lock.tryUnlockRead());
- assertFalse(lock.tryUnlockWrite());
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
-
- /**
- * write-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testWriteUnlock_IMSE() {
- StampedLock lock = new StampedLock();
- try {
- lock.unlockWrite(0L);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * write-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testWriteUnlock_IMSE2() {
- StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- lock.unlockWrite(s);
- try {
- lock.unlockWrite(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * write-unlocking after readlock throws IllegalMonitorStateException
- */
- public void testWriteUnlock_IMSE3() {
- StampedLock lock = new StampedLock();
- long s = lock.readLock();
- try {
- lock.unlockWrite(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * read-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testReadUnlock_IMSE() {
- StampedLock lock = new StampedLock();
- long s = lock.readLock();
- lock.unlockRead(s);
- try {
- lock.unlockRead(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * read-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testReadUnlock_IMSE2() {
- StampedLock lock = new StampedLock();
- try {
- lock.unlockRead(0L);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * read-unlocking after writeLock throws IllegalMonitorStateException
- */
- public void testReadUnlock_IMSE3() {
- StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- try {
- lock.unlockRead(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * validate(0) fails
- */
- public void testValidate0() {
- StampedLock lock = new StampedLock();
- assertFalse(lock.validate(0L));
- }
-
- /**
- * A stamp obtained from a successful lock operation validates
- */
- public void testValidate() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- s = lock.readLock();
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- }
-
- /**
- * A stamp obtained from an unsuccessful lock operation does not validate
- */
- public void testValidate2() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s;
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue(lock.validate(s));
- assertFalse(lock.validate(lock.tryWriteLock()));
- assertFalse(lock.validate(lock.tryWriteLock(10L, MILLISECONDS)));
- assertFalse(lock.validate(lock.tryReadLock()));
- assertFalse(lock.validate(lock.tryReadLock(10L, MILLISECONDS)));
- assertFalse(lock.validate(lock.tryOptimisticRead()));
- lock.unlockWrite(s);
- }
-
- /**
- * writeLockInterruptibly is interruptible
- */
- public void testWriteLockInterruptibly_Interruptible()
- throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.writeLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * timed tryWriteLock is interruptible
- */
- public void testWriteTryLock_Interruptible() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS);
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * readLockInterruptibly is interruptible
- */
- public void testReadLockInterruptibly_Interruptible()
- throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.readLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * timed tryReadLock is interruptible
- */
- public void testReadTryLock_Interruptible() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS);
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * tryWriteLock on an unlocked lock succeeds
- */
- public void testWriteTryLock() {
- final StampedLock lock = new StampedLock();
- long s = lock.tryWriteLock();
- assertTrue(s != 0L);
- assertTrue(lock.isWriteLocked());
- long s2 = lock.tryWriteLock();
- assertEquals(s2, 0L);
- releaseWriteLock(lock, s);
- }
-
- /**
- * tryWriteLock fails if locked
- */
- public void testWriteTryLockWhenLocked() {
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long ws = lock.tryWriteLock();
- assertTrue(ws == 0L);
- }});
-
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * tryReadLock fails if write-locked
- */
- public void testReadTryLockWhenLocked() {
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long rs = lock.tryReadLock();
- assertEquals(rs, 0L);
- }});
-
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * Multiple threads can hold a read lock when not write-locked
- */
- public void testMultipleReadLocks() {
- final StampedLock lock = new StampedLock();
- final long s = lock.readLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- long s2 = lock.tryReadLock();
- assertTrue(s2 != 0L);
- lock.unlockRead(s2);
- long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
- assertTrue(s3 != 0L);
- lock.unlockRead(s3);
- long s4 = lock.readLock();
- lock.unlockRead(s4);
- }});
-
- awaitTermination(t);
- lock.unlockRead(s);
- }
-
- /**
- * A writelock succeeds only after a reading thread unlocks
- */
- public void testWriteAfterReadLock() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long rs = lock.readLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- running.countDown();
- long s = lock.writeLock();
- lock.unlockWrite(s);
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- assertFalse(lock.isWriteLocked());
- lock.unlockRead(rs);
- awaitTermination(t);
- assertFalse(lock.isWriteLocked());
- }
-
- /**
- * A writelock succeeds only after reading threads unlock
- */
- public void testWriteAfterMultipleReadLocks() {
- final StampedLock lock = new StampedLock();
- long s = lock.readLock();
- Thread t1 = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long rs = lock.readLock();
- lock.unlockRead(rs);
- }});
-
- awaitTermination(t1);
-
- Thread t2 = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long ws = lock.writeLock();
- lock.unlockWrite(ws);
- }});
-
- assertFalse(lock.isWriteLocked());
- lock.unlockRead(s);
- awaitTermination(t2);
- assertFalse(lock.isWriteLocked());
- }
-
- /**
- * Readlocks succeed only after a writing thread unlocks
- */
- public void testReadAfterWriteLock() {
- final StampedLock lock = new StampedLock();
- final long s = lock.writeLock();
- Thread t1 = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long rs = lock.readLock();
- lock.unlockRead(rs);
- }});
- Thread t2 = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long rs = lock.readLock();
- lock.unlockRead(rs);
- }});
-
- releaseWriteLock(lock, s);
- awaitTermination(t1);
- awaitTermination(t2);
- }
-
- /**
- * tryReadLock succeeds if readlocked but not writelocked
- */
- public void testTryLockWhenReadLocked() {
- final StampedLock lock = new StampedLock();
- long s = lock.readLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long rs = lock.tryReadLock();
- threadAssertTrue(rs != 0L);
- lock.unlockRead(rs);
- }});
-
- awaitTermination(t);
- lock.unlockRead(s);
- }
-
- /**
- * tryWriteLock fails when readlocked
- */
- public void testWriteTryLockWhenReadLocked() {
- final StampedLock lock = new StampedLock();
- long s = lock.readLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() {
- long ws = lock.tryWriteLock();
- threadAssertEquals(ws, 0L);
- }});
-
- awaitTermination(t);
- lock.unlockRead(s);
- }
-
- /**
- * timed tryWriteLock times out if locked
- */
- public void testWriteTryLock_Timeout() {
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
- long timeoutMillis = 10;
- long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
- assertEquals(ws, 0L);
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- }});
-
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * timed tryReadLock times out if write-locked
- */
- public void testReadTryLock_Timeout() {
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
- long timeoutMillis = 10;
- long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
- assertEquals(rs, 0L);
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- }});
-
- awaitTermination(t);
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
- }
-
- /**
- * writeLockInterruptibly succeeds if unlocked, else is interruptible
- */
- public void testWriteLockInterruptibly() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLockInterruptibly();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.writeLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- assertTrue(lock.isWriteLocked());
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * readLockInterruptibly succeeds if lock free else is interruptible
- */
- public void testReadLockInterruptibly() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s;
- s = lock.readLockInterruptibly();
- lock.unlockRead(s);
- s = lock.writeLockInterruptibly();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.readLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * A serialized lock deserializes as unlocked
- */
- public void testSerialization() {
- StampedLock lock = new StampedLock();
- lock.writeLock();
- StampedLock clone = serialClone(lock);
- assertTrue(lock.isWriteLocked());
- assertFalse(clone.isWriteLocked());
- long s = clone.writeLock();
- assertTrue(clone.isWriteLocked());
- clone.unlockWrite(s);
- assertFalse(clone.isWriteLocked());
- }
-
- /**
- * toString indicates current lock state
- */
- public void testToString() {
- StampedLock lock = new StampedLock();
- assertTrue(lock.toString().contains("Unlocked"));
- long s = lock.writeLock();
- assertTrue(lock.toString().contains("Write-locked"));
- lock.unlockWrite(s);
- s = lock.readLock();
- assertTrue(lock.toString().contains("Read-locks"));
- }
-
- /**
- * tryOptimisticRead succeeds and validates if unlocked, fails if locked
- */
- public void testValidateOptimistic() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.writeLock()) != 0L);
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockRead(s);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockRead(s);
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- }
-
- /**
- * tryOptimisticRead stamp does not validate if a write lock intervenes
- */
- public void testValidateOptimisticWriteLocked() {
- StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue((s = lock.writeLock()) != 0L);
- assertFalse(lock.validate(p));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- }
-
- /**
- * tryOptimisticRead stamp does not validate if a write lock
- * intervenes in another thread
- */
- public void testValidateOptimisticWriteLocked2()
- throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- lock.writeLockInterruptibly();
- running.countDown();
- lock.writeLockInterruptibly();
- }});
-
- running.await();
- assertFalse(lock.validate(p));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- t.interrupt();
- awaitTermination(t);
- }
-
- /**
- * tryConvertToOptimisticRead succeeds and validates if successfully locked,
- */
- public void testTryConvertToOptimisticRead() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s, p;
- s = 0L;
- assertFalse((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
- }
-
- /**
- * tryConvertToReadLock succeeds and validates if successfully locked
- * or lock free;
- */
- public void testTryConvertToReadLock() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s, p;
- s = 0L;
- assertFalse((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- lock.unlockRead(p);
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(p);
- }
-
- /**
- * tryConvertToWriteLock succeeds and validates if successfully locked
- * or lock free;
- */
- public void testTryConvertToWriteLock() throws InterruptedException {
- StampedLock lock = new StampedLock();
- long s, p;
- s = 0L;
- assertFalse((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- lock.unlockWrite(p);
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockWrite(p);
- }
-
- /**
- * asWriteLock can be locked and unlocked
- */
- public void testAsWriteLock() {
- StampedLock sl = new StampedLock();
- Lock lock = sl.asWriteLock();
- lock.lock();
- assertFalse(lock.tryLock());
- lock.unlock();
- assertTrue(lock.tryLock());
- }
-
- /**
- * asReadLock can be locked and unlocked
- */
- public void testAsReadLock() {
- StampedLock sl = new StampedLock();
- Lock lock = sl.asReadLock();
- lock.lock();
- lock.unlock();
- assertTrue(lock.tryLock());
- }
-
- /**
- * asReadWriteLock.writeLock can be locked and unlocked
- */
- public void testAsReadWriteLockWriteLock() {
- StampedLock sl = new StampedLock();
- Lock lock = sl.asReadWriteLock().writeLock();
- lock.lock();
- assertFalse(lock.tryLock());
- lock.unlock();
- assertTrue(lock.tryLock());
- }
-
- /**
- * asReadWriteLock.readLock can be locked and unlocked
- */
- public void testAsReadWriteLockReadLock() {
- StampedLock sl = new StampedLock();
- Lock lock = sl.asReadWriteLock().readLock();
- lock.lock();
- lock.unlock();
- assertTrue(lock.tryLock());
- }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
index 9d3f212..605a955 100644
--- a/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
@@ -25,7 +25,7 @@
public class SynchronousQueueTest extends JSR166TestCase {
- // android-note: These tests have been moved into their own separate
+ // android-note: These tests have been moved into their own separate
// classes to work around CTS issues.
//
// public static class Fair extends BlockingQueueTest {
@@ -33,19 +33,17 @@
// return new SynchronousQueue(true);
// }
// }
-
+ //
// public static class NonFair extends BlockingQueueTest {
// protected BlockingQueue emptyCollection() {
// return new SynchronousQueue(false);
// }
// }
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
//
// public static void main(String[] args) {
// main(suite(), args);
// }
+ //
// public static Test suite() {
// return newTestSuite(SynchronousQueueTest.class,
// new Fair().testSuite(),
@@ -264,6 +262,7 @@
pleaseOffer.countDown();
startTime = System.nanoTime();
assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
Thread.currentThread().interrupt();
try {
@@ -278,15 +277,13 @@
shouldThrow();
} catch (InterruptedException success) {}
assertFalse(Thread.interrupted());
-
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}});
await(pleaseOffer);
long startTime = System.nanoTime();
try { assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS)); }
catch (InterruptedException e) { threadUnexpectedException(e); }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertTrue(millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
await(pleaseInterrupt);
assertThreadStaysAlive(t);
@@ -477,24 +474,24 @@
public void testOfferInExecutor_fair() { testOfferInExecutor(true); }
public void testOfferInExecutor(boolean fair) {
final SynchronousQueue q = new SynchronousQueue(fair);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertFalse(q.offer(one));
- threadsStarted.await();
- assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
- assertEquals(0, q.remainingCapacity());
- }});
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(one));
+ threadsStarted.await();
+ assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- assertSame(one, q.take());
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
}
/**
@@ -505,22 +502,22 @@
public void testPollInExecutor(boolean fair) {
final SynchronousQueue q = new SynchronousQueue(fair);
final CheckedBarrier threadsStarted = new CheckedBarrier(2);
- final ExecutorService executor = Executors.newFixedThreadPool(2);
- try (PoolCleaner cleaner = cleaner(executor)) {
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- assertNull(q.poll());
- threadsStarted.await();
- assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(q.isEmpty());
- }});
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(q.isEmpty());
+ }});
- executor.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadsStarted.await();
- q.put(one);
- }});
- }
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
}
/**
@@ -598,12 +595,10 @@
}});
ArrayList l = new ArrayList();
- int drained;
- while ((drained = q.drainTo(l, 1)) == 0) Thread.yield();
- assertEquals(1, drained);
+ delay(SHORT_DELAY_MS);
+ q.drainTo(l, 1);
assertEquals(1, l.size());
- while ((drained = q.drainTo(l, 1)) == 0) Thread.yield();
- assertEquals(1, drained);
+ q.drainTo(l, 1);
assertEquals(2, l.size());
assertTrue(l.contains(one));
assertTrue(l.contains(two));
diff --git a/jsr166-tests/src/test/java/jsr166/SystemTest.java b/jsr166-tests/src/test/java/jsr166/SystemTest.java
index 412ce17..6918374 100644
--- a/jsr166-tests/src/test/java/jsr166/SystemTest.java
+++ b/jsr166-tests/src/test/java/jsr166/SystemTest.java
@@ -19,7 +19,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(SystemTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandom8Test.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandom8Test.java
deleted file mode 100644
index 614af83..0000000
--- a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandom8Test.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * 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 jsr166;
-
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.LongAdder;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class ThreadLocalRandom8Test extends JSR166TestCase {
-
- // android-note: Removed because the CTS runner does a bad job of
- // retrying tests that have suite() declarations.
- //
- // public static void main(String[] args) {
- // main(suite(), args);
- // }
- // public static Test suite() {
- // return new TestSuite(ThreadLocalRandom8Test.class);
- // }
-
- // max sampled int bound
- static final int MAX_INT_BOUND = (1 << 26);
-
- // max sampled long bound
- static final long MAX_LONG_BOUND = (1L << 42);
-
- // Number of replications for other checks
- static final int REPS =
- Integer.getInteger("ThreadLocalRandom8Test.reps", 4);
-
- /**
- * Invoking sized ints, long, doubles, with negative sizes throws
- * IllegalArgumentException
- */
- // TODO(streams):
- // public void testBadStreamSize() {
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // Runnable[] throwingActions = {
- // () -> r.ints(-1L),
- // () -> r.ints(-1L, 2, 3),
- // () -> r.longs(-1L),
- // () -> r.longs(-1L, -1L, 1L),
- // () -> r.doubles(-1L),
- // () -> r.doubles(-1L, .5, .6),
- // };
- // assertThrows(IllegalArgumentException.class, throwingActions);
- // }
-
- // /**
- // * Invoking bounded ints, long, doubles, with illegal bounds throws
- // * IllegalArgumentException
- // */
- // public void testBadStreamBounds() {
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // Runnable[] throwingActions = {
- // () -> r.ints(2, 1),
- // () -> r.ints(10, 42, 42),
- // () -> r.longs(-1L, -1L),
- // () -> r.longs(10, 1L, -2L),
- // () -> r.doubles(0.0, 0.0),
- // () -> r.doubles(10, .5, .4),
- // };
- // assertThrows(IllegalArgumentException.class, throwingActions);
- // }
-
- // /**
- // * A parallel sized stream of ints generates the given number of values
- // */
- // public void testIntsCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 0;
- // for (int reps = 0; reps < REPS; ++reps) {
- // counter.reset();
- // r.ints(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // size += 524959;
- // }
- // }
-
- // /**
- // * A parallel sized stream of longs generates the given number of values
- // */
- // public void testLongsCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 0;
- // for (int reps = 0; reps < REPS; ++reps) {
- // counter.reset();
- // r.longs(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // size += 524959;
- // }
- // }
-
- // /**
- // * A parallel sized stream of doubles generates the given number of values
- // */
- // public void testDoublesCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 0;
- // for (int reps = 0; reps < REPS; ++reps) {
- // counter.reset();
- // r.doubles(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // size += 524959;
- // }
- // }
-
- // /**
- // * Each of a parallel sized stream of bounded ints is within bounds
- // */
- // public void testBoundedInts() {
- // AtomicInteger fails = new AtomicInteger(0);
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 12345L;
- // for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
- // for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
- // final int lo = least, hi = bound;
- // r.ints(size, lo, hi).parallel().forEach(
- // x -> {
- // if (x < lo || x >= hi)
- // fails.getAndIncrement(); });
- // }
- // }
- // assertEquals(0, fails.get());
- // }
-
- // /**
- // * Each of a parallel sized stream of bounded longs is within bounds
- // */
- // public void testBoundedLongs() {
- // AtomicInteger fails = new AtomicInteger(0);
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 123L;
- // for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
- // for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
- // final long lo = least, hi = bound;
- // r.longs(size, lo, hi).parallel().forEach(
- // x -> {
- // if (x < lo || x >= hi)
- // fails.getAndIncrement(); });
- // }
- // }
- // assertEquals(0, fails.get());
- // }
-
- // /**
- // * Each of a parallel sized stream of bounded doubles is within bounds
- // */
- // public void testBoundedDoubles() {
- // AtomicInteger fails = new AtomicInteger(0);
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 456;
- // for (double least = 0.00011; least < 1.0e20; least *= 9) {
- // for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
- // final double lo = least, hi = bound;
- // r.doubles(size, lo, hi).parallel().forEach(
- // x -> {
- // if (x < lo || x >= hi)
- // fails.getAndIncrement(); });
- // }
- // }
- // assertEquals(0, fails.get());
- // }
-
- // /**
- // * A parallel unsized stream of ints generates at least 100 values
- // */
- // public void testUnsizedIntsCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.ints().limit(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
- // /**
- // * A parallel unsized stream of longs generates at least 100 values
- // */
- // public void testUnsizedLongsCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.longs().limit(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
- // /**
- // * A parallel unsized stream of doubles generates at least 100 values
- // */
- // public void testUnsizedDoublesCount() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.doubles().limit(size).parallel().forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
- // /**
- // * A sequential unsized stream of ints generates at least 100 values
- // */
- // public void testUnsizedIntsCountSeq() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.ints().limit(size).forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
- // /**
- // * A sequential unsized stream of longs generates at least 100 values
- // */
- // public void testUnsizedLongsCountSeq() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.longs().limit(size).forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
- // /**
- // * A sequential unsized stream of doubles generates at least 100 values
- // */
- // public void testUnsizedDoublesCountSeq() {
- // LongAdder counter = new LongAdder();
- // ThreadLocalRandom r = ThreadLocalRandom.current();
- // long size = 100;
- // r.doubles().limit(size).forEach(x -> counter.increment());
- // assertEquals(size, counter.sum());
- // }
-
-}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
index 5d9f894..4ae141d 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
@@ -22,7 +22,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ThreadLocalRandomTest.class);
+ // return new TestSuite(...);
// }
/*
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
index 8bfcf70..7f5f072 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
@@ -19,7 +19,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ThreadLocalTest.class);
+ // return new TestSuite(...);
// }
static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
index a502392..5f38d39 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
@@ -9,14 +9,12 @@
package jsr166;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -32,7 +30,6 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -47,7 +44,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ThreadPoolExecutorSubclassTest.class);
+ // return new TestSuite(...);
// }
static class CustomTask<V> implements RunnableFuture<V> {
@@ -106,13 +103,11 @@
}
lock.lock();
try {
- if (!done) {
- result = v;
- exception = e;
- done = true;
- thread = null;
- cond.signalAll();
- }
+ result = v;
+ exception = e;
+ done = true;
+ thread = null;
+ cond.signalAll();
}
finally { lock.unlock(); }
}
@@ -121,8 +116,6 @@
try {
while (!done)
cond.await();
- if (cancelled)
- throw new CancellationException();
if (exception != null)
throw new ExecutionException(exception);
return result;
@@ -134,13 +127,12 @@
long nanos = unit.toNanos(timeout);
lock.lock();
try {
- while (!done) {
- if (nanos <= 0L)
+ for (;;) {
+ if (done) break;
+ if (nanos < 0)
throw new TimeoutException();
nanos = cond.awaitNanos(nanos);
}
- if (cancelled)
- throw new CancellationException();
if (exception != null)
throw new ExecutionException(exception);
return result;
@@ -237,14 +229,18 @@
public void testExecute() throws InterruptedException {
final ThreadPoolExecutor p =
new CustomTPE(1, 1,
- 2 * LONG_DELAY_MS, MILLISECONDS,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch done = new CountDownLatch(1);
- final Runnable task = new CheckedRunnable() {
- public void realRun() { done.countDown(); }};
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
p.execute(task);
- assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -253,22 +249,25 @@
* thread becomes active
*/
public void testGetActiveCount() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new CustomTPE(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getActiveCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getActiveCount());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -276,48 +275,28 @@
* prestartCoreThread starts a thread if under corePoolSize, else doesn't
*/
public void testPrestartCoreThread() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 6,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(0, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(1, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(2, p.getPoolSize());
- assertFalse(p.prestartCoreThread());
- assertEquals(2, p.getPoolSize());
- p.setCorePoolSize(4);
- assertTrue(p.prestartCoreThread());
- assertEquals(3, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(4, p.getPoolSize());
- assertFalse(p.prestartCoreThread());
- assertEquals(4, p.getPoolSize());
- }
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(1, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ assertFalse(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
}
/**
* prestartAllCoreThreads starts all corePoolSize threads
*/
public void testPrestartAllCoreThreads() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 6,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(0, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(2, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(2, p.getPoolSize());
- p.setCorePoolSize(4);
- p.prestartAllCoreThreads();
- assertEquals(4, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(4, p.getPoolSize());
- }
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
}
/**
@@ -329,10 +308,10 @@
new CustomTPE(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch threadProceed = new CountDownLatch(1);
- final CountDownLatch threadDone = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
@@ -351,6 +330,8 @@
fail("timed out");
Thread.yield();
}
+ } finally {
+ joinPool(p);
}
}
@@ -358,72 +339,52 @@
* getCorePoolSize returns size given in constructor if not otherwise set
*/
public void testGetCorePoolSize() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getCorePoolSize());
- }
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
}
/**
* getKeepAliveTime returns value given in constructor if not otherwise set
*/
public void testGetKeepAliveTime() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 2,
- 1000, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getKeepAliveTime(SECONDS));
- }
+ ThreadPoolExecutor p = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getKeepAliveTime(TimeUnit.SECONDS));
+ joinPool(p);
}
/**
* getThreadFactory returns factory in constructor if not set
*/
public void testGetThreadFactory() {
- final ThreadFactory threadFactory = new SimpleThreadFactory();
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- threadFactory,
- new NoOpREHandler());
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), tf, new NoOpREHandler());
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory sets the thread factory returned by getThreadFactory
*/
public void testSetThreadFactory() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- ThreadFactory threadFactory = new SimpleThreadFactory();
- p.setThreadFactory(threadFactory);
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ ThreadFactory tf = new SimpleThreadFactory();
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
* setThreadFactory(null) throws NPE
*/
public void testSetThreadFactoryNull() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setThreadFactory(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -431,15 +392,10 @@
* getRejectedExecutionHandler returns handler in constructor if not set
*/
public void testGetRejectedExecutionHandler() {
- final RejectedExecutionHandler handler = new NoOpREHandler();
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- handler);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(handler, p.getRejectedExecutionHandler());
- }
+ RejectedExecutionHandler h = new NoOpREHandler();
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
}
/**
@@ -447,30 +403,24 @@
* getRejectedExecutionHandler
*/
public void testSetRejectedExecutionHandler() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- RejectedExecutionHandler handler = new NoOpREHandler();
- p.setRejectedExecutionHandler(handler);
- assertSame(handler, p.getRejectedExecutionHandler());
- }
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ RejectedExecutionHandler h = new NoOpREHandler();
+ p.setRejectedExecutionHandler(h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
}
/**
* setRejectedExecutionHandler(null) throws NPE
*/
public void testSetRejectedExecutionHandlerNull() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setRejectedExecutionHandler(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setRejectedExecutionHandler(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -480,25 +430,28 @@
*/
public void testGetLargestPoolSize() throws InterruptedException {
final int THREADS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new CustomTPE(THREADS, THREADS,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getLargestPoolSize());
- final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
for (int i = 0; i < THREADS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadsStarted.countDown();
- await(done);
+ done.await();
assertEquals(THREADS, p.getLargestPoolSize());
}});
- await(threadsStarted);
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
assertEquals(THREADS, p.getLargestPoolSize());
}
- assertEquals(THREADS, p.getLargestPoolSize());
}
/**
@@ -506,17 +459,9 @@
* otherwise set
*/
public void testGetMaximumPoolSize() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 3,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(3, p.getMaximumPoolSize());
- p.setMaximumPoolSize(5);
- assertEquals(5, p.getMaximumPoolSize());
- p.setMaximumPoolSize(4);
- assertEquals(4, p.getMaximumPoolSize());
- }
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(2, p.getMaximumPoolSize());
+ joinPool(p);
}
/**
@@ -524,22 +469,25 @@
* become active
*/
public void testGetPoolSize() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getPoolSize());
- final CountDownLatch threadStarted = new CountDownLatch(1);
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getPoolSize());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -547,53 +495,38 @@
* getTaskCount increases, but doesn't overestimate, when tasks submitted
*/
public void testGetTaskCount() throws InterruptedException {
- final int TASKS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ assertEquals(1, p.getTaskCount());
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- for (int i = 0; i < TASKS; i++) {
- assertEquals(1 + i, p.getTaskCount());
- p.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadStarted.countDown();
- assertEquals(1 + TASKS, p.getTaskCount());
- await(done);
- }});
- }
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(1 + TASKS, p.getCompletedTaskCount());
}
/**
* isShutdown is false before shutdown, true after
*/
public void testIsShutdown() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.isShutdown());
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.isShutdown());
- }
+
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.isShutdown());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ joinPool(p);
}
/**
@@ -604,24 +537,25 @@
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertFalse(p.isTerminating());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminating());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
}
/**
@@ -632,55 +566,59 @@
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertFalse(p.isTerminating());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminating());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
}
/**
* getQueue returns the work queue, which contains queued tasks
*/
public void testGetQueue() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
final ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
FutureTask[] tasks = new FutureTask[5];
for (int i = 0; i < tasks.length; i++) {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() throws InterruptedException {
threadStarted.countDown();
assertSame(q, p.getQueue());
- await(done);
+ done.await();
return Boolean.TRUE;
}};
tasks[i] = new FutureTask(task);
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertSame(q, p.getQueue());
assertFalse(q.contains(tasks[0]));
assertTrue(q.contains(tasks[tasks.length - 1]));
assertEquals(tasks.length - 1, q.size());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -688,24 +626,24 @@
* remove(task) removes queued task, and fails to remove active task
*/
public void testRemove() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
final ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- Runnable[] tasks = new Runnable[6];
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ Runnable[] tasks = new Runnable[6];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
for (int i = 0; i < tasks.length; i++) {
tasks[i] = new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadStarted.countDown();
- await(done);
- }};
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.remove(tasks[0]));
assertTrue(q.contains(tasks[4]));
assertTrue(q.contains(tasks[3]));
@@ -715,6 +653,9 @@
assertTrue(q.contains(tasks[3]));
assertTrue(p.remove(tasks[3]));
assertFalse(q.contains(tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -729,19 +670,19 @@
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- FutureTask[] tasks = new FutureTask[5];
+ FutureTask[] tasks = new FutureTask[5];
+ try {
for (int i = 0; i < tasks.length; i++) {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
return Boolean.TRUE;
}};
tasks[i] = new FutureTask(task);
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(tasks.length, p.getTaskCount());
assertEquals(tasks.length - 1, q.size());
assertEquals(1L, p.getActiveCount());
@@ -754,47 +695,29 @@
p.purge(); // Nothing to do
assertEquals(tasks.length - 3, q.size());
assertEquals(tasks.length - 2, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * shutdownNow returns a list containing tasks that were not run
*/
- public void testShutdownNow() throws InterruptedException {
- final int poolSize = 2;
- final int count = 5;
- final AtomicInteger ran = new AtomicInteger(0);
- final ThreadPoolExecutor p =
- new CustomTPE(poolSize, poolSize,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
- Runnable waiter = new CheckedRunnable() { public void realRun() {
- threadsStarted.countDown();
- try {
- MILLISECONDS.sleep(2 * LONG_DELAY_MS);
- } catch (InterruptedException success) {}
- ran.getAndIncrement();
- }};
- for (int i = 0; i < count; i++)
- p.execute(waiter);
- await(threadsStarted);
- assertEquals(poolSize, p.getActiveCount());
- assertEquals(0, p.getCompletedTaskCount());
- final List<Runnable> queuedTasks;
+ public void testShutdownNow() {
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List l;
try {
- queuedTasks = p.shutdownNow();
- } catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
+ for (int i = 0; i < 5; i++)
+ p.execute(new MediumPossiblyInterruptedRunnable());
+ }
+ finally {
+ try {
+ l = p.shutdownNow();
+ } catch (SecurityException ok) { return; }
}
assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- assertEquals(count - poolSize, queuedTasks.size());
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertEquals(poolSize, ran.get());
- assertEquals(poolSize, p.getCompletedTaskCount());
+ assertTrue(l.size() <= 4);
}
// Exception Tests
@@ -804,8 +727,7 @@
*/
public void testConstructor1() {
try {
- new CustomTPE(-1, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -815,8 +737,7 @@
*/
public void testConstructor2() {
try {
- new CustomTPE(1, -1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -826,8 +747,7 @@
*/
public void testConstructor3() {
try {
- new CustomTPE(1, 0, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -837,8 +757,7 @@
*/
public void testConstructor4() {
try {
- new CustomTPE(1, 2, -1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -848,8 +767,7 @@
*/
public void testConstructor5() {
try {
- new CustomTPE(2, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -859,7 +777,7 @@
*/
public void testConstructorNullPointerException() {
try {
- new CustomTPE(1, 2, 1L, SECONDS, null);
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -869,9 +787,7 @@
*/
public void testConstructor6() {
try {
- new CustomTPE(-1, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory());
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -881,9 +797,7 @@
*/
public void testConstructor7() {
try {
- new CustomTPE(1,-1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory());
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -893,9 +807,7 @@
*/
public void testConstructor8() {
try {
- new CustomTPE(1, 0, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory());
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -905,9 +817,7 @@
*/
public void testConstructor9() {
try {
- new CustomTPE(1, 2, -1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory());
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -917,9 +827,7 @@
*/
public void testConstructor10() {
try {
- new CustomTPE(2, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory());
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -929,7 +837,7 @@
*/
public void testConstructorNullPointerException2() {
try {
- new CustomTPE(1, 2, 1L, SECONDS, null, new SimpleThreadFactory());
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory());
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -939,9 +847,8 @@
*/
public void testConstructorNullPointerException3() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- (ThreadFactory) null);
+ ThreadFactory f = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -951,9 +858,7 @@
*/
public void testConstructor11() {
try {
- new CustomTPE(-1, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new NoOpREHandler());
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -963,9 +868,7 @@
*/
public void testConstructor12() {
try {
- new CustomTPE(1, -1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new NoOpREHandler());
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -975,9 +878,7 @@
*/
public void testConstructor13() {
try {
- new CustomTPE(1, 0, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new NoOpREHandler());
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -987,9 +888,7 @@
*/
public void testConstructor14() {
try {
- new CustomTPE(1, 2, -1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new NoOpREHandler());
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -999,9 +898,7 @@
*/
public void testConstructor15() {
try {
- new CustomTPE(2, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new NoOpREHandler());
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1011,9 +908,7 @@
*/
public void testConstructorNullPointerException4() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
- null,
- new NoOpREHandler());
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new NoOpREHandler());
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -1023,9 +918,8 @@
*/
public void testConstructorNullPointerException5() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- (RejectedExecutionHandler) null);
+ RejectedExecutionHandler r = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),r);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -1035,10 +929,7 @@
*/
public void testConstructor16() {
try {
- new CustomTPE(-1, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1048,10 +939,7 @@
*/
public void testConstructor17() {
try {
- new CustomTPE(1, -1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1061,10 +949,7 @@
*/
public void testConstructor18() {
try {
- new CustomTPE(1, 0, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1074,10 +959,7 @@
*/
public void testConstructor19() {
try {
- new CustomTPE(1, 2, -1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1087,10 +969,7 @@
*/
public void testConstructor20() {
try {
- new CustomTPE(2, 1, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (IllegalArgumentException success) {}
}
@@ -1100,10 +979,7 @@
*/
public void testConstructorNullPointerException6() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
- null,
- new SimpleThreadFactory(),
- new NoOpREHandler());
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory(),new NoOpREHandler());
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -1113,10 +989,8 @@
*/
public void testConstructorNullPointerException7() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10),
- new SimpleThreadFactory(),
- (RejectedExecutionHandler) null);
+ RejectedExecutionHandler r = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),r);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -1126,7 +1000,8 @@
*/
public void testConstructorNullPointerException8() {
try {
- new CustomTPE(1, 2, 1L, SECONDS,
+ new CustomTPE(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
(ThreadFactory) null,
new NoOpREHandler());
@@ -1138,15 +1013,15 @@
* execute throws RejectedExecutionException if saturated.
*/
public void testSaturatedExecute() {
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() throws InterruptedException {
- await(done);
+ done.await();
}};
for (int i = 0; i < 2; ++i)
p.execute(task);
@@ -1157,6 +1032,9 @@
} catch (RejectedExecutionException success) {}
assertTrue(p.getTaskCount() <= 2);
}
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -1164,26 +1042,24 @@
* executor using CallerRunsPolicy runs task if saturated.
*/
public void testSaturatedExecute2() {
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.CallerRunsPolicy());
- try (PoolCleaner cleaner = cleaner(p, done)) {
- Runnable blocker = new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- await(done);
- }};
- p.execute(blocker);
+ RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
- for (int i = 0; i < tasks.length; i++)
+ for (int i = 0; i < tasks.length; ++i)
tasks[i] = new TrackedNoOpRunnable();
- for (int i = 0; i < tasks.length; i++)
+ TrackedLongRunnable mr = new TrackedLongRunnable();
+ p.execute(mr);
+ for (int i = 0; i < tasks.length; ++i)
p.execute(tasks[i]);
- for (int i = 1; i < tasks.length; i++)
+ for (int i = 1; i < tasks.length; ++i)
assertTrue(tasks[i].done);
- assertFalse(tasks[0].done); // waiting in queue
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
}
@@ -1191,88 +1067,77 @@
* executor using DiscardPolicy drops task if saturated.
*/
public void testSaturatedExecute3() {
- final TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
- for (int i = 0; i < tasks.length; ++i)
- tasks[i] = new TrackedNoOpRunnable();
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
+ RejectedExecutionHandler h = new CustomTPE.DiscardPolicy();
+ ThreadPoolExecutor p =
new CustomTPE(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.DiscardPolicy());
- try (PoolCleaner cleaner = cleaner(p, done)) {
- p.execute(awaiter(done));
-
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ p.execute(new TrackedLongRunnable());
for (TrackedNoOpRunnable task : tasks)
p.execute(task);
- for (int i = 1; i < tasks.length; i++)
- assertFalse(tasks[i].done);
+ for (TrackedNoOpRunnable task : tasks)
+ assertFalse(task.done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
- for (int i = 1; i < tasks.length; i++)
- assertFalse(tasks[i].done);
- assertTrue(tasks[0].done); // was waiting in queue
}
/**
* executor using DiscardOldestPolicy drops oldest task if saturated.
*/
public void testSaturatedExecute4() {
- final CountDownLatch done = new CountDownLatch(1);
- LatchAwaiter r1 = awaiter(done);
- LatchAwaiter r2 = awaiter(done);
- LatchAwaiter r3 = awaiter(done);
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.DiscardOldestPolicy());
- try (PoolCleaner cleaner = cleaner(p, done)) {
- assertEquals(LatchAwaiter.NEW, r1.state);
- assertEquals(LatchAwaiter.NEW, r2.state);
- assertEquals(LatchAwaiter.NEW, r3.state);
- p.execute(r1);
+ RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+ try {
+ p.execute(new TrackedLongRunnable());
+ TrackedLongRunnable r2 = new TrackedLongRunnable();
p.execute(r2);
assertTrue(p.getQueue().contains(r2));
+ TrackedNoOpRunnable r3 = new TrackedNoOpRunnable();
p.execute(r3);
assertFalse(p.getQueue().contains(r2));
assertTrue(p.getQueue().contains(r3));
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
- assertEquals(LatchAwaiter.DONE, r1.state);
- assertEquals(LatchAwaiter.NEW, r2.state);
- assertEquals(LatchAwaiter.DONE, r3.state);
}
/**
* execute throws RejectedExecutionException if shutdown
*/
public void testRejectedExecutionExceptionOnShutdown() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1));
+ ThreadPoolExecutor p =
+ new CustomTPE(1,1,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(1));
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(new NoOpRunnable());
- shouldThrow();
- } catch (RejectedExecutionException success) {}
- }
+ try {
+ p.execute(new NoOpRunnable());
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+
+ joinPool(p);
}
/**
* execute using CallerRunsPolicy drops task on shutdown
*/
public void testCallerRunsOnShutdown() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.CallerRunsPolicy());
+ RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1280,16 +1145,16 @@
* execute using DiscardPolicy drops task on shutdown
*/
public void testDiscardOnShutdown() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.DiscardPolicy());
+ RejectedExecutionHandler h = new CustomTPE.DiscardPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1297,17 +1162,16 @@
* execute using DiscardOldestPolicy drops task on shutdown
*/
public void testDiscardOldestOnShutdown() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new CustomTPE.DiscardOldestPolicy());
+ RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1315,32 +1179,30 @@
* execute(null) throws NPE
*/
public void testExecuteNull() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- 1L, SECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ ThreadPoolExecutor p = null;
+ try {
+ p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ p.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(p);
}
/**
* setCorePoolSize of negative value throws IllegalArgumentException
*/
public void testCorePoolSizeIllegalArgumentException() {
- final ThreadPoolExecutor p =
- new CustomTPE(1, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setCorePoolSize(-1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ThreadPoolExecutor p =
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setCorePoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1348,16 +1210,16 @@
* if given a value less the core pool size
*/
public void testMaximumPoolSizeIllegalArgumentException() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 3,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setMaximumPoolSize(1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1365,16 +1227,16 @@
* if given a negative value
*/
public void testMaximumPoolSizeIllegalArgumentException2() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 3,
- LONG_DELAY_MS,
- MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setMaximumPoolSize(-1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1382,16 +1244,17 @@
* when given a negative value
*/
public void testKeepAliveTimeIllegalArgumentException() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 3,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setKeepAliveTime(-1, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+
+ try {
+ p.setKeepAliveTime(-1,MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1399,11 +1262,9 @@
*/
public void testTerminated() {
CustomTPE p = new CustomTPE();
- try (PoolCleaner cleaner = cleaner(p)) {
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.terminatedCalled());
- assertTrue(p.isShutdown());
- }
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.terminatedCalled());
+ joinPool(p);
}
/**
@@ -1411,7 +1272,7 @@
*/
public void testBeforeAfter() throws InterruptedException {
CustomTPE p = new CustomTPE();
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
final CountDownLatch done = new CountDownLatch(1);
p.execute(new CheckedRunnable() {
public void realRun() {
@@ -1421,6 +1282,9 @@
assertEquals(0, done.getCount());
assertTrue(p.afterCalled());
assertTrue(p.beforeCalled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
}
@@ -1428,14 +1292,13 @@
* completed submit of callable returns result
*/
public void testSubmitCallable() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
Future<String> future = e.submit(new StringTask());
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1443,14 +1306,13 @@
* completed submit of runnable returns successfully
*/
public void testSubmitRunnable() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
Future<?> future = e.submit(new NoOpRunnable());
future.get();
assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -1458,14 +1320,13 @@
* completed submit of (runnable, result) returns result
*/
public void testSubmitRunnable2() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1473,15 +1334,13 @@
* invokeAny(null) throws NPE
*/
public void testInvokeAny1() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1489,15 +1348,13 @@
* invokeAny(empty collection) throws IAE
*/
public void testInvokeAny2() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1506,19 +1363,17 @@
*/
public void testInvokeAny3() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1526,19 +1381,16 @@
* invokeAny(c) throws ExecutionException if no task completes
*/
public void testInvokeAny4() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1546,16 +1398,15 @@
* invokeAny(c) returns result of some task
*/
public void testInvokeAny5() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1563,15 +1414,13 @@
* invokeAll(null) throws NPE
*/
public void testInvokeAll1() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1579,13 +1428,12 @@
* invokeAll(empty collection) returns empty collection
*/
public void testInvokeAll2() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1593,18 +1441,16 @@
* invokeAll(c) throws NPE if c has null elements
*/
public void testInvokeAll3() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1612,21 +1458,18 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testInvokeAll4() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures = e.invokeAll(l);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1634,11 +1477,8 @@
* invokeAll(c) returns results of all completed tasks
*/
public void testInvokeAll5() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -1646,6 +1486,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1653,15 +1495,13 @@
* timed invokeAny(null) throws NPE
*/
public void testTimedInvokeAny1() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1669,17 +1509,15 @@
* timed invokeAny(,,null) throws NPE
*/
public void testTimedInvokeAnyNullTimeUnit() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1687,16 +1525,13 @@
* timed invokeAny(empty collection) throws IAE
*/
public void testTimedInvokeAny2() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1705,19 +1540,17 @@
*/
public void testTimedInvokeAny3() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1725,21 +1558,16 @@
* timed invokeAny(c) throws ExecutionException if no task completes
*/
public void testTimedInvokeAny4() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1747,18 +1575,15 @@
* timed invokeAny(c) returns result of some task
*/
public void testTimedInvokeAny5() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -1766,15 +1591,13 @@
* timed invokeAll(null) throws NPE
*/
public void testTimedInvokeAll1() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1782,17 +1605,15 @@
* timed invokeAll(,,null) throws NPE
*/
public void testTimedInvokeAllNullTimeUnit() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1800,14 +1621,12 @@
* timed invokeAll(empty collection) returns empty collection
*/
public void testTimedInvokeAll2() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1815,18 +1634,16 @@
* timed invokeAll(c) throws NPE if c has null elements
*/
public void testTimedInvokeAll3() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1834,22 +1651,19 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testTimedInvokeAll4() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1857,19 +1671,18 @@
* timed invokeAll(c) returns results of all completed tasks
*/
public void testTimedInvokeAll5() throws Exception {
- final ExecutorService e =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1877,40 +1690,21 @@
* timed invokeAll(c) cancels tasks not completed by timeout
*/
public void testTimedInvokeAll6() throws Exception {
- for (long timeout = timeoutMillis();;) {
- final CountDownLatch done = new CountDownLatch(1);
- final Callable<String> waiter = new CheckedCallable<String>() {
- public String realCall() {
- try { done.await(LONG_DELAY_MS, MILLISECONDS); }
- catch (InterruptedException ok) {}
- return "1"; }};
- final ExecutorService p =
- new CustomTPE(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- List<Callable<String>> tasks = new ArrayList<>();
- tasks.add(new StringTask("0"));
- tasks.add(waiter);
- tasks.add(new StringTask("2"));
- long startTime = System.nanoTime();
- List<Future<String>> futures =
- p.invokeAll(tasks, timeout, MILLISECONDS);
- assertEquals(tasks.size(), futures.size());
- assertTrue(millisElapsedSince(startTime) >= timeout);
- for (Future future : futures)
- assertTrue(future.isDone());
- assertTrue(futures.get(1).isCancelled());
- try {
- assertEquals("0", futures.get(0).get());
- assertEquals("2", futures.get(2).get());
- break;
- } catch (CancellationException retryWithLongerTimeout) {
- timeout *= 2;
- if (timeout >= LONG_DELAY_MS / 2)
- fail("expected exactly one task to be cancelled");
- }
- }
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -1924,7 +1718,7 @@
LONG_DELAY_MS, MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
new FailingThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
final int TASKS = 100;
final CountDownLatch done = new CountDownLatch(TASKS);
for (int k = 0; k < TASKS; ++k)
@@ -1933,6 +1727,8 @@
done.countDown();
}});
assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(e);
}
}
@@ -1940,40 +1736,38 @@
* allowsCoreThreadTimeOut is by default false.
*/
public void testAllowsCoreThreadTimeOut() {
- final ThreadPoolExecutor p =
- new CustomTPE(2, 2,
- 1000, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.allowsCoreThreadTimeOut());
- }
+ ThreadPoolExecutor p = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.allowsCoreThreadTimeOut());
+ joinPool(p);
}
/**
* allowCoreThreadTimeOut(true) causes idle threads to time out
*/
public void testAllowCoreThreadTimeOut_true() throws Exception {
- long keepAliveTime = timeoutMillis();
+ long coreThreadTimeOut = SHORT_DELAY_MS;
final ThreadPoolExecutor p =
new CustomTPE(2, 10,
- keepAliveTime, MILLISECONDS,
+ coreThreadTimeOut, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
p.allowCoreThreadTimeOut(true);
p.execute(new CheckedRunnable() {
- public void realRun() {
+ public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getPoolSize());
}});
await(threadStarted);
- delay(keepAliveTime);
+ delay(coreThreadTimeOut);
long startTime = System.nanoTime();
while (p.getPoolSize() > 0
&& millisElapsedSince(startTime) < LONG_DELAY_MS)
Thread.yield();
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
assertEquals(0, p.getPoolSize());
+ } finally {
+ joinPool(p);
}
}
@@ -1981,59 +1775,23 @@
* allowCoreThreadTimeOut(false) causes idle threads not to time out
*/
public void testAllowCoreThreadTimeOut_false() throws Exception {
- long keepAliveTime = timeoutMillis();
+ long coreThreadTimeOut = SHORT_DELAY_MS;
final ThreadPoolExecutor p =
new CustomTPE(2, 10,
- keepAliveTime, MILLISECONDS,
+ coreThreadTimeOut, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
p.allowCoreThreadTimeOut(false);
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertTrue(p.getPoolSize() >= 1);
}});
- delay(2 * keepAliveTime);
+ delay(2 * coreThreadTimeOut);
assertTrue(p.getPoolSize() >= 1);
- }
- }
-
- /**
- * get(cancelled task) throws CancellationException
- * (in part, a test of CustomTPE itself)
- */
- public void testGet_cancelled() throws Exception {
- final CountDownLatch done = new CountDownLatch(1);
- final ExecutorService e =
- new CustomTPE(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- try (PoolCleaner cleaner = cleaner(e, done)) {
- final CountDownLatch blockerStarted = new CountDownLatch(1);
- final List<Future<?>> futures = new ArrayList<>();
- for (int i = 0; i < 2; i++) {
- Runnable r = new CheckedRunnable() { public void realRun()
- throws Throwable {
- blockerStarted.countDown();
- assertTrue(done.await(2 * LONG_DELAY_MS, MILLISECONDS));
- }};
- futures.add(e.submit(r));
- }
- await(blockerStarted);
- for (Future<?> future : futures) future.cancel(false);
- for (Future<?> future : futures) {
- try {
- future.get();
- shouldThrow();
- } catch (CancellationException success) {}
- try {
- future.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (CancellationException success) {}
- assertTrue(future.isCancelled());
- assertTrue(future.isDone());
- }
+ } finally {
+ joinPool(p);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
index 7fe26f4..52a7002 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
@@ -10,14 +10,12 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -31,7 +29,6 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -44,7 +41,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ThreadPoolExecutorTest.class);
+ // return new TestSuite(...);
// }
static class ExtendedTPE extends ThreadPoolExecutor {
@@ -92,12 +89,16 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch done = new CountDownLatch(1);
- final Runnable task = new CheckedRunnable() {
- public void realRun() { done.countDown(); }};
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
p.execute(task);
- assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
}
}
@@ -106,22 +107,25 @@
* thread becomes active
*/
public void testGetActiveCount() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getActiveCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getActiveCount());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -130,25 +134,17 @@
*/
public void testPrestartCoreThread() {
final ThreadPoolExecutor p =
- new ThreadPoolExecutor(2, 6,
+ new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(0, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(1, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(2, p.getPoolSize());
- assertFalse(p.prestartCoreThread());
- assertEquals(2, p.getPoolSize());
- p.setCorePoolSize(4);
- assertTrue(p.prestartCoreThread());
- assertEquals(3, p.getPoolSize());
- assertTrue(p.prestartCoreThread());
- assertEquals(4, p.getPoolSize());
- assertFalse(p.prestartCoreThread());
- assertEquals(4, p.getPoolSize());
- }
+ assertEquals(0, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(1, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ assertFalse(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
}
/**
@@ -156,21 +152,15 @@
*/
public void testPrestartAllCoreThreads() {
final ThreadPoolExecutor p =
- new ThreadPoolExecutor(2, 6,
+ new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(0, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(2, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(2, p.getPoolSize());
- p.setCorePoolSize(4);
- p.prestartAllCoreThreads();
- assertEquals(4, p.getPoolSize());
- p.prestartAllCoreThreads();
- assertEquals(4, p.getPoolSize());
- }
+ assertEquals(0, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
}
/**
@@ -182,10 +172,10 @@
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch threadProceed = new CountDownLatch(1);
- final CountDownLatch threadDone = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
@@ -204,6 +194,8 @@
fail("timed out");
Thread.yield();
}
+ } finally {
+ joinPool(p);
}
}
@@ -215,9 +207,8 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getCorePoolSize());
- }
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
}
/**
@@ -228,25 +219,23 @@
new ThreadPoolExecutor(2, 2,
1000, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(1, p.getKeepAliveTime(SECONDS));
- }
+ assertEquals(1, p.getKeepAliveTime(TimeUnit.SECONDS));
+ joinPool(p);
}
/**
* getThreadFactory returns factory in constructor if not set
*/
public void testGetThreadFactory() {
- ThreadFactory threadFactory = new SimpleThreadFactory();
+ ThreadFactory tf = new SimpleThreadFactory();
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
- threadFactory,
+ tf,
new NoOpREHandler());
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(threadFactory, p.getThreadFactory());
- }
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
@@ -257,11 +246,10 @@
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- ThreadFactory threadFactory = new SimpleThreadFactory();
- p.setThreadFactory(threadFactory);
- assertSame(threadFactory, p.getThreadFactory());
- }
+ ThreadFactory tf = new SimpleThreadFactory();
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
}
/**
@@ -272,11 +260,12 @@
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setThreadFactory(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -284,15 +273,14 @@
* getRejectedExecutionHandler returns handler in constructor if not set
*/
public void testGetRejectedExecutionHandler() {
- final RejectedExecutionHandler handler = new NoOpREHandler();
+ final RejectedExecutionHandler h = new NoOpREHandler();
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
- handler);
- try (PoolCleaner cleaner = cleaner(p)) {
- assertSame(handler, p.getRejectedExecutionHandler());
- }
+ h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
}
/**
@@ -304,11 +292,10 @@
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- RejectedExecutionHandler handler = new NoOpREHandler();
- p.setRejectedExecutionHandler(handler);
- assertSame(handler, p.getRejectedExecutionHandler());
- }
+ RejectedExecutionHandler h = new NoOpREHandler();
+ p.setRejectedExecutionHandler(h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
}
/**
@@ -319,11 +306,12 @@
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setRejectedExecutionHandler(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ p.setRejectedExecutionHandler(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
}
}
@@ -333,25 +321,28 @@
*/
public void testGetLargestPoolSize() throws InterruptedException {
final int THREADS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(THREADS, THREADS,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getLargestPoolSize());
- final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
for (int i = 0; i < THREADS; i++)
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadsStarted.countDown();
- await(done);
+ done.await();
assertEquals(THREADS, p.getLargestPoolSize());
}});
- await(threadsStarted);
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
assertEquals(THREADS, p.getLargestPoolSize());
}
- assertEquals(THREADS, p.getLargestPoolSize());
}
/**
@@ -363,13 +354,8 @@
new ThreadPoolExecutor(2, 3,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertEquals(3, p.getMaximumPoolSize());
- p.setMaximumPoolSize(5);
- assertEquals(5, p.getMaximumPoolSize());
- p.setMaximumPoolSize(4);
- assertEquals(4, p.getMaximumPoolSize());
- }
+ assertEquals(3, p.getMaximumPoolSize());
+ joinPool(p);
}
/**
@@ -377,22 +363,25 @@
* become active
*/
public void testGetPoolSize() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getPoolSize());
- final CountDownLatch threadStarted = new CountDownLatch(1);
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertEquals(1, p.getPoolSize());
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -400,38 +389,26 @@
* getTaskCount increases, but doesn't overestimate, when tasks submitted
*/
public void testGetTaskCount() throws InterruptedException {
- final int TASKS = 3;
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertEquals(0, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ assertEquals(1, p.getTaskCount());
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(1, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
- for (int i = 0; i < TASKS; i++) {
- assertEquals(1 + i, p.getTaskCount());
- p.execute(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- threadStarted.countDown();
- assertEquals(1 + TASKS, p.getTaskCount());
- await(done);
- }});
- }
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(0, p.getCompletedTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
- assertEquals(1 + TASKS, p.getTaskCount());
- assertEquals(1 + TASKS, p.getCompletedTaskCount());
}
/**
@@ -442,11 +419,10 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.isShutdown());
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.isShutdown());
- }
+ assertFalse(p.isShutdown());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ joinPool(p);
}
/**
@@ -457,28 +433,26 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.isTerminated());
- assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
- assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
- assertFalse(p.awaitTermination(-1L, NANOSECONDS));
- assertFalse(p.awaitTermination(-1L, MILLISECONDS));
- assertFalse(p.awaitTermination(0L, NANOSECONDS));
- assertFalse(p.awaitTermination(0L, MILLISECONDS));
- long timeoutNanos = 999999L;
- long startTime = System.nanoTime();
- assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
- assertTrue(System.nanoTime() - startTime >= timeoutNanos);
- assertFalse(p.isTerminated());
- startTime = System.nanoTime();
- long timeoutMillis = timeoutMillis();
- assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- assertFalse(p.isTerminated());
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- }
+ assertFalse(p.isTerminated());
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
+ assertFalse(p.awaitTermination(-1L, NANOSECONDS));
+ assertFalse(p.awaitTermination(-1L, MILLISECONDS));
+ assertFalse(p.awaitTermination(0L, NANOSECONDS));
+ assertFalse(p.awaitTermination(0L, MILLISECONDS));
+ long timeoutNanos = 999999L;
+ long startTime = System.nanoTime();
+ assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
+ assertTrue(System.nanoTime() - startTime >= timeoutNanos);
+ assertFalse(p.isTerminated());
+ startTime = System.nanoTime();
+ long timeoutMillis = timeoutMillis();
+ assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ assertFalse(p.isTerminated());
+ p.shutdown();
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
}
/**
@@ -489,24 +463,24 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
- assertFalse(p.isTerminating());
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
- assertFalse(p.isTerminating());
+ assertFalse(p.isTerminated());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
}
/**
@@ -517,55 +491,59 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
- final CountDownLatch done = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
assertFalse(p.isTerminating());
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(p.isTerminating());
threadStarted.countDown();
- await(done);
+ done.await();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.isTerminating());
done.countDown();
+ } finally {
try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertFalse(p.isTerminating());
}
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
}
/**
* getQueue returns the work queue, which contains queued tasks
*/
public void testGetQueue() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
FutureTask[] tasks = new FutureTask[5];
for (int i = 0; i < tasks.length; i++) {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() throws InterruptedException {
threadStarted.countDown();
assertSame(q, p.getQueue());
- await(done);
+ done.await();
return Boolean.TRUE;
}};
tasks[i] = new FutureTask(task);
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertSame(q, p.getQueue());
assertFalse(q.contains(tasks[0]));
assertTrue(q.contains(tasks[tasks.length - 1]));
assertEquals(tasks.length - 1, q.size());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -573,24 +551,24 @@
* remove(task) removes queued task, and fails to remove active task
*/
public void testRemove() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- Runnable[] tasks = new Runnable[6];
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ Runnable[] tasks = new Runnable[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
for (int i = 0; i < tasks.length; i++) {
tasks[i] = new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
}};
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertFalse(p.remove(tasks[0]));
assertTrue(q.contains(tasks[4]));
assertTrue(q.contains(tasks[3]));
@@ -600,6 +578,9 @@
assertTrue(q.contains(tasks[3]));
assertTrue(p.remove(tasks[3]));
assertFalse(q.contains(tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -614,19 +595,19 @@
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
q);
- try (PoolCleaner cleaner = cleaner(p, done)) {
- FutureTask[] tasks = new FutureTask[5];
+ FutureTask[] tasks = new FutureTask[5];
+ try {
for (int i = 0; i < tasks.length; i++) {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
return Boolean.TRUE;
}};
tasks[i] = new FutureTask(task);
p.execute(tasks[i]);
}
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
assertEquals(tasks.length, p.getTaskCount());
assertEquals(tasks.length - 1, q.size());
assertEquals(1L, p.getActiveCount());
@@ -639,47 +620,32 @@
p.purge(); // Nothing to do
assertEquals(tasks.length - 3, q.size());
assertEquals(tasks.length - 2, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
/**
- * shutdownNow returns a list containing tasks that were not run,
- * and those tasks are drained from the queue
+ * shutdownNow returns a list containing tasks that were not run
*/
- public void testShutdownNow() throws InterruptedException {
- final int poolSize = 2;
- final int count = 5;
- final AtomicInteger ran = new AtomicInteger(0);
+ public void testShutdownNow() {
final ThreadPoolExecutor p =
- new ThreadPoolExecutor(poolSize, poolSize,
+ new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
- Runnable waiter = new CheckedRunnable() { public void realRun() {
- threadsStarted.countDown();
- try {
- MILLISECONDS.sleep(2 * LONG_DELAY_MS);
- } catch (InterruptedException success) {}
- ran.getAndIncrement();
- }};
- for (int i = 0; i < count; i++)
- p.execute(waiter);
- await(threadsStarted);
- assertEquals(poolSize, p.getActiveCount());
- assertEquals(0, p.getCompletedTaskCount());
- final List<Runnable> queuedTasks;
+ List l;
try {
- queuedTasks = p.shutdownNow();
- } catch (SecurityException ok) {
- return; // Allowed in case test doesn't have privs
+ for (int i = 0; i < 5; i++)
+ p.execute(new MediumPossiblyInterruptedRunnable());
+ }
+ finally {
+ try {
+ l = p.shutdownNow();
+ } catch (SecurityException ok) { return; }
}
assertTrue(p.isShutdown());
- assertTrue(p.getQueue().isEmpty());
- assertEquals(count - poolSize, queuedTasks.size());
- assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
- assertTrue(p.isTerminated());
- assertEquals(poolSize, ran.get());
- assertEquals(poolSize, p.getCompletedTaskCount());
+ assertTrue(l.size() <= 4);
}
// Exception Tests
@@ -689,7 +655,8 @@
*/
public void testConstructor1() {
try {
- new ThreadPoolExecutor(-1, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -700,7 +667,8 @@
*/
public void testConstructor2() {
try {
- new ThreadPoolExecutor(1, -1, 1L, SECONDS,
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -711,7 +679,8 @@
*/
public void testConstructor3() {
try {
- new ThreadPoolExecutor(1, 0, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -722,7 +691,8 @@
*/
public void testConstructor4() {
try {
- new ThreadPoolExecutor(1, 2, -1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -733,7 +703,8 @@
*/
public void testConstructor5() {
try {
- new ThreadPoolExecutor(2, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
shouldThrow();
} catch (IllegalArgumentException success) {}
@@ -744,7 +715,8 @@
*/
public void testConstructorNullPointerException() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
(BlockingQueue) null);
shouldThrow();
} catch (NullPointerException success) {}
@@ -755,7 +727,8 @@
*/
public void testConstructor6() {
try {
- new ThreadPoolExecutor(-1, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory());
shouldThrow();
@@ -767,7 +740,8 @@
*/
public void testConstructor7() {
try {
- new ThreadPoolExecutor(1, -1, 1L, SECONDS,
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory());
shouldThrow();
@@ -779,7 +753,8 @@
*/
public void testConstructor8() {
try {
- new ThreadPoolExecutor(1, 0, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory());
shouldThrow();
@@ -791,7 +766,8 @@
*/
public void testConstructor9() {
try {
- new ThreadPoolExecutor(1, 2, -1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory());
shouldThrow();
@@ -803,7 +779,8 @@
*/
public void testConstructor10() {
try {
- new ThreadPoolExecutor(2, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory());
shouldThrow();
@@ -815,7 +792,8 @@
*/
public void testConstructorNullPointerException2() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
(BlockingQueue) null,
new SimpleThreadFactory());
shouldThrow();
@@ -827,7 +805,8 @@
*/
public void testConstructorNullPointerException3() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
(ThreadFactory) null);
shouldThrow();
@@ -839,7 +818,8 @@
*/
public void testConstructor11() {
try {
- new ThreadPoolExecutor(-1, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NoOpREHandler());
shouldThrow();
@@ -851,7 +831,8 @@
*/
public void testConstructor12() {
try {
- new ThreadPoolExecutor(1, -1, 1L, SECONDS,
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NoOpREHandler());
shouldThrow();
@@ -863,7 +844,8 @@
*/
public void testConstructor13() {
try {
- new ThreadPoolExecutor(1, 0, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NoOpREHandler());
shouldThrow();
@@ -875,7 +857,8 @@
*/
public void testConstructor14() {
try {
- new ThreadPoolExecutor(1, 2, -1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NoOpREHandler());
shouldThrow();
@@ -887,7 +870,8 @@
*/
public void testConstructor15() {
try {
- new ThreadPoolExecutor(2, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NoOpREHandler());
shouldThrow();
@@ -899,7 +883,8 @@
*/
public void testConstructorNullPointerException4() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
(BlockingQueue) null,
new NoOpREHandler());
shouldThrow();
@@ -911,7 +896,8 @@
*/
public void testConstructorNullPointerException5() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
(RejectedExecutionHandler) null);
shouldThrow();
@@ -923,7 +909,8 @@
*/
public void testConstructor16() {
try {
- new ThreadPoolExecutor(-1, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -936,7 +923,8 @@
*/
public void testConstructor17() {
try {
- new ThreadPoolExecutor(1, -1, 1L, SECONDS,
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -949,7 +937,8 @@
*/
public void testConstructor18() {
try {
- new ThreadPoolExecutor(1, 0, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -962,7 +951,8 @@
*/
public void testConstructor19() {
try {
- new ThreadPoolExecutor(1, 2, -1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -975,7 +965,8 @@
*/
public void testConstructor20() {
try {
- new ThreadPoolExecutor(2, 1, 1L, SECONDS,
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -988,7 +979,8 @@
*/
public void testConstructorNullPointerException6() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
(BlockingQueue) null,
new SimpleThreadFactory(),
new NoOpREHandler());
@@ -1001,7 +993,8 @@
*/
public void testConstructorNullPointerException7() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new SimpleThreadFactory(),
(RejectedExecutionHandler) null);
@@ -1014,7 +1007,8 @@
*/
public void testConstructorNullPointerException8() {
try {
- new ThreadPoolExecutor(1, 2, 1L, SECONDS,
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
(ThreadFactory) null,
new NoOpREHandler());
@@ -1026,28 +1020,31 @@
* get of submitted callable throws InterruptedException if interrupted
*/
public void testInterruptedSubmit() throws InterruptedException {
- final CountDownLatch done = new CountDownLatch(1);
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
- 60, SECONDS,
+ 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws Exception {
Callable task = new CheckedCallable<Boolean>() {
public Boolean realCall() throws InterruptedException {
threadStarted.countDown();
- await(done);
+ done.await();
return Boolean.TRUE;
}};
p.submit(task).get();
}});
- await(threadStarted);
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
t.interrupt();
- awaitTermination(t);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -1055,15 +1052,15 @@
* execute throws RejectedExecutionException if saturated.
*/
public void testSaturatedExecute() {
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() throws InterruptedException {
- await(done);
+ done.await();
}};
for (int i = 0; i < 2; ++i)
p.execute(task);
@@ -1074,6 +1071,9 @@
} catch (RejectedExecutionException success) {}
assertTrue(p.getTaskCount() <= 2);
}
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -1081,15 +1081,15 @@
* submit(runnable) throws RejectedExecutionException if saturated.
*/
public void testSaturatedSubmitRunnable() {
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() throws InterruptedException {
- await(done);
+ done.await();
}};
for (int i = 0; i < 2; ++i)
p.submit(task);
@@ -1100,6 +1100,9 @@
} catch (RejectedExecutionException success) {}
assertTrue(p.getTaskCount() <= 2);
}
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -1107,15 +1110,15 @@
* submit(callable) throws RejectedExecutionException if saturated.
*/
public void testSaturatedSubmitCallable() {
- final CountDownLatch done = new CountDownLatch(1);
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1));
- try (PoolCleaner cleaner = cleaner(p, done)) {
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
Runnable task = new CheckedRunnable() {
public void realRun() throws InterruptedException {
- await(done);
+ done.await();
}};
for (int i = 0; i < 2; ++i)
p.submit(Executors.callable(task));
@@ -1126,6 +1129,9 @@
} catch (RejectedExecutionException success) {}
assertTrue(p.getTaskCount() <= 2);
}
+ } finally {
+ done.countDown();
+ joinPool(p);
}
}
@@ -1133,28 +1139,26 @@
* executor using CallerRunsPolicy runs task if saturated.
*/
public void testSaturatedExecute2() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy();
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS,
MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1),
- new ThreadPoolExecutor.CallerRunsPolicy());
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch done = new CountDownLatch(1);
- Runnable blocker = new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- await(done);
- }};
- p.execute(blocker);
+ h);
+ try {
TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
- for (int i = 0; i < tasks.length; i++)
+ for (int i = 0; i < tasks.length; ++i)
tasks[i] = new TrackedNoOpRunnable();
- for (int i = 0; i < tasks.length; i++)
+ TrackedLongRunnable mr = new TrackedLongRunnable();
+ p.execute(mr);
+ for (int i = 0; i < tasks.length; ++i)
p.execute(tasks[i]);
- for (int i = 1; i < tasks.length; i++)
+ for (int i = 1; i < tasks.length; ++i)
assertTrue(tasks[i].done);
- assertFalse(tasks[0].done); // waiting in queue
- done.countDown();
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
}
@@ -1162,72 +1166,67 @@
* executor using DiscardPolicy drops task if saturated.
*/
public void testSaturatedExecute3() {
- final CountDownLatch done = new CountDownLatch(1);
- final TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
- for (int i = 0; i < tasks.length; ++i)
- tasks[i] = new TrackedNoOpRunnable();
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy();
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(1),
- new ThreadPoolExecutor.DiscardPolicy());
- try (PoolCleaner cleaner = cleaner(p, done)) {
- p.execute(awaiter(done));
-
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ p.execute(new TrackedLongRunnable());
for (TrackedNoOpRunnable task : tasks)
p.execute(task);
- for (int i = 1; i < tasks.length; i++)
- assertFalse(tasks[i].done);
+ for (TrackedNoOpRunnable task : tasks)
+ assertFalse(task.done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
- for (int i = 1; i < tasks.length; i++)
- assertFalse(tasks[i].done);
- assertTrue(tasks[0].done); // was waiting in queue
}
/**
* executor using DiscardOldestPolicy drops oldest task if saturated.
*/
public void testSaturatedExecute4() {
- final CountDownLatch done = new CountDownLatch(1);
- LatchAwaiter r1 = awaiter(done);
- LatchAwaiter r2 = awaiter(done);
- LatchAwaiter r3 = awaiter(done);
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy();
final ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1),
- new ThreadPoolExecutor.DiscardOldestPolicy());
- try (PoolCleaner cleaner = cleaner(p, done)) {
- assertEquals(LatchAwaiter.NEW, r1.state);
- assertEquals(LatchAwaiter.NEW, r2.state);
- assertEquals(LatchAwaiter.NEW, r3.state);
- p.execute(r1);
+ h);
+ try {
+ p.execute(new TrackedLongRunnable());
+ TrackedLongRunnable r2 = new TrackedLongRunnable();
p.execute(r2);
assertTrue(p.getQueue().contains(r2));
+ TrackedNoOpRunnable r3 = new TrackedNoOpRunnable();
p.execute(r3);
assertFalse(p.getQueue().contains(r2));
assertTrue(p.getQueue().contains(r3));
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
- assertEquals(LatchAwaiter.DONE, r1.state);
- assertEquals(LatchAwaiter.NEW, r2.state);
- assertEquals(LatchAwaiter.DONE, r3.state);
}
/**
* execute throws RejectedExecutionException if shutdown
*/
public void testRejectedExecutionExceptionOnShutdown() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1));
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(new NoOpRunnable());
- shouldThrow();
- } catch (RejectedExecutionException success) {}
- }
+ try {
+ p.execute(new NoOpRunnable());
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+
+ joinPool(p);
}
/**
@@ -1241,10 +1240,12 @@
new ArrayBlockingQueue<Runnable>(1), h);
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1252,17 +1253,20 @@
* execute using DiscardPolicy drops task on shutdown
*/
public void testDiscardOnShutdown() {
- final ThreadPoolExecutor p =
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy();
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1),
- new ThreadPoolExecutor.DiscardPolicy());
+ h);
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1270,17 +1274,20 @@
* execute using DiscardOldestPolicy drops task on shutdown
*/
public void testDiscardOldestOnShutdown() {
- final ThreadPoolExecutor p =
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy();
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 1,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1),
- new ThreadPoolExecutor.DiscardOldestPolicy());
+ h);
try { p.shutdown(); } catch (SecurityException ok) { return; }
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
TrackedNoOpRunnable r = new TrackedNoOpRunnable();
p.execute(r);
assertFalse(r.done);
+ } finally {
+ joinPool(p);
}
}
@@ -1288,32 +1295,34 @@
* execute(null) throws NPE
*/
public void testExecuteNull() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 2,
- 1L, SECONDS,
+ LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.execute(null);
- shouldThrow();
- } catch (NullPointerException success) {}
- }
+ try {
+ p.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(p);
}
/**
* setCorePoolSize of negative value throws IllegalArgumentException
*/
public void testCorePoolSizeIllegalArgumentException() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(1, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setCorePoolSize(-1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ p.setCorePoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1321,16 +1330,18 @@
* given a value less the core pool size
*/
public void testMaximumPoolSizeIllegalArgumentException() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 3,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setMaximumPoolSize(1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ p.setMaximumPoolSize(1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1338,45 +1349,18 @@
* if given a negative value
*/
public void testMaximumPoolSizeIllegalArgumentException2() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 3,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setMaximumPoolSize(-1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ p.setMaximumPoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
- }
-
- /**
- * Configuration changes that allow core pool size greater than
- * max pool size result in IllegalArgumentException.
- */
- public void testPoolSizeInvariants() {
- final ThreadPoolExecutor p =
- new ThreadPoolExecutor(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- for (int s = 1; s < 5; s++) {
- p.setMaximumPoolSize(s);
- p.setCorePoolSize(s);
- try {
- p.setMaximumPoolSize(s - 1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
- assertEquals(s, p.getCorePoolSize());
- assertEquals(s, p.getMaximumPoolSize());
- try {
- p.setCorePoolSize(s + 1);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
- assertEquals(s, p.getCorePoolSize());
- assertEquals(s, p.getMaximumPoolSize());
- }
- }
+ joinPool(p);
}
/**
@@ -1384,16 +1368,18 @@
* when given a negative value
*/
public void testKeepAliveTimeIllegalArgumentException() {
- final ThreadPoolExecutor p =
+ ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 3,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- try {
- p.setKeepAliveTime(-1, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ p.setKeepAliveTime(-1,MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
}
+ joinPool(p);
}
/**
@@ -1401,11 +1387,9 @@
*/
public void testTerminated() {
ExtendedTPE p = new ExtendedTPE();
- try (PoolCleaner cleaner = cleaner(p)) {
- try { p.shutdown(); } catch (SecurityException ok) { return; }
- assertTrue(p.terminatedCalled());
- assertTrue(p.isShutdown());
- }
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.terminatedCalled());
+ joinPool(p);
}
/**
@@ -1413,7 +1397,7 @@
*/
public void testBeforeAfter() throws InterruptedException {
ExtendedTPE p = new ExtendedTPE();
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
final CountDownLatch done = new CountDownLatch(1);
p.execute(new CheckedRunnable() {
public void realRun() {
@@ -1423,6 +1407,9 @@
assertEquals(0, done.getCount());
assertTrue(p.afterCalled());
assertTrue(p.beforeCalled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
}
}
@@ -1430,14 +1417,16 @@
* completed submit of callable returns result
*/
public void testSubmitCallable() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<String> future = e.submit(new StringTask());
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1445,14 +1434,16 @@
* completed submit of runnable returns successfully
*/
public void testSubmitRunnable() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<?> future = e.submit(new NoOpRunnable());
future.get();
assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
}
}
@@ -1460,14 +1451,16 @@
* completed submit of (runnable, result) returns result
*/
public void testSubmitRunnable2() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
String result = future.get();
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1475,15 +1468,16 @@
* invokeAny(null) throws NPE
*/
public void testInvokeAny1() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1491,15 +1485,16 @@
* invokeAny(empty collection) throws IAE
*/
public void testInvokeAny2() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>());
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1512,15 +1507,16 @@
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1528,19 +1524,19 @@
* invokeAny(c) throws ExecutionException if no task completes
*/
public void testInvokeAny4() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1548,16 +1544,18 @@
* invokeAny(c) returns result of some task
*/
public void testInvokeAny5() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
String result = e.invokeAny(l);
assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
}
}
@@ -1565,15 +1563,16 @@
* invokeAll(null) throws NPE
*/
public void testInvokeAll1() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1581,13 +1580,15 @@
* invokeAll(empty collection) returns empty collection
*/
public void testInvokeAll2() throws InterruptedException {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1595,18 +1596,19 @@
* invokeAll(c) throws NPE if c has null elements
*/
public void testInvokeAll3() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1614,11 +1616,11 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testInvokeAll4() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new NPETask());
List<Future<String>> futures = e.invokeAll(l);
@@ -1629,6 +1631,8 @@
} catch (ExecutionException success) {
assertTrue(success.getCause() instanceof NullPointerException);
}
+ } finally {
+ joinPool(e);
}
}
@@ -1636,11 +1640,11 @@
* invokeAll(c) returns results of all completed tasks
*/
public void testInvokeAll5() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
@@ -1648,6 +1652,8 @@
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1655,15 +1661,16 @@
* timed invokeAny(null) throws NPE
*/
public void testTimedInvokeAny1() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1671,17 +1678,18 @@
* timed invokeAny(,,null) throws NPE
*/
public void testTimedInvokeAnyNullTimeUnit() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1689,16 +1697,16 @@
* timed invokeAny(empty collection) throws IAE
*/
public void testTimedInvokeAny2() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAny(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (IllegalArgumentException success) {}
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1711,15 +1719,16 @@
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(latchAwaitingStringTask(latch));
- l.add(null);
- try {
- e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
latch.countDown();
+ joinPool(e);
}
}
@@ -1727,21 +1736,19 @@
* timed invokeAny(c) throws ExecutionException if no task completes
*/
public void testTimedInvokeAny4() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- try {
- e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1749,18 +1756,18 @@
* timed invokeAny(c) returns result of some task
*/
public void testTimedInvokeAny5() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- long startTime = System.nanoTime();
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
- String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertSame(TEST_STRING, result);
- assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ } finally {
+ joinPool(e);
}
}
@@ -1768,15 +1775,16 @@
* timed invokeAll(null) throws NPE
*/
public void testTimedInvokeAll1() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- try {
- e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1784,17 +1792,18 @@
* timed invokeAll(,,null) throws NPE
*/
public void testTimedInvokeAllNullTimeUnit() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, null);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1802,14 +1811,15 @@
* timed invokeAll(empty collection) returns empty collection
*/
public void testTimedInvokeAll2() throws InterruptedException {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(),
- MEDIUM_DELAY_MS, MILLISECONDS);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
}
}
@@ -1817,18 +1827,19 @@
* timed invokeAll(c) throws NPE if c has null elements
*/
public void testTimedInvokeAll3() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new StringTask());
- l.add(null);
- try {
- e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (NullPointerException success) {}
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
}
}
@@ -1836,22 +1847,22 @@
* get of element of invokeAll(c) throws exception on failed task
*/
public void testTimedInvokeAll4() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
- List<Callable<String>> l = new ArrayList<Callable<String>>();
- l.add(new NPETask());
- List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
- assertEquals(1, futures.size());
- try {
- futures.get(0).get();
- shouldThrow();
- } catch (ExecutionException success) {
- assertTrue(success.getCause() instanceof NullPointerException);
- }
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
}
}
@@ -1859,19 +1870,21 @@
* timed invokeAll(c) returns results of all completed tasks
*/
public void testTimedInvokeAll5() throws Exception {
- final ExecutorService e =
+ ExecutorService e =
new ThreadPoolExecutor(2, 2,
LONG_DELAY_MS, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
List<Callable<String>> l = new ArrayList<Callable<String>>();
l.add(new StringTask());
l.add(new StringTask());
List<Future<String>> futures =
- e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
assertEquals(2, futures.size());
for (Future<String> future : futures)
assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
}
}
@@ -1879,40 +1892,24 @@
* timed invokeAll(c) cancels tasks not completed by timeout
*/
public void testTimedInvokeAll6() throws Exception {
- for (long timeout = timeoutMillis();;) {
- final CountDownLatch done = new CountDownLatch(1);
- final Callable<String> waiter = new CheckedCallable<String>() {
- public String realCall() {
- try { done.await(LONG_DELAY_MS, MILLISECONDS); }
- catch (InterruptedException ok) {}
- return "1"; }};
- final ExecutorService p =
- new ThreadPoolExecutor(2, 2,
- LONG_DELAY_MS, MILLISECONDS,
- new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p, done)) {
- List<Callable<String>> tasks = new ArrayList<>();
- tasks.add(new StringTask("0"));
- tasks.add(waiter);
- tasks.add(new StringTask("2"));
- long startTime = System.nanoTime();
- List<Future<String>> futures =
- p.invokeAll(tasks, timeout, MILLISECONDS);
- assertEquals(tasks.size(), futures.size());
- assertTrue(millisElapsedSince(startTime) >= timeout);
- for (Future future : futures)
- assertTrue(future.isDone());
- assertTrue(futures.get(1).isCancelled());
- try {
- assertEquals("0", futures.get(0).get());
- assertEquals("2", futures.get(2).get());
- break;
- } catch (CancellationException retryWithLongerTimeout) {
- timeout *= 2;
- if (timeout >= LONG_DELAY_MS / 2)
- fail("expected exactly one task to be cancelled");
- }
- }
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
}
}
@@ -1926,7 +1923,7 @@
LONG_DELAY_MS, MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
new FailingThreadFactory());
- try (PoolCleaner cleaner = cleaner(e)) {
+ try {
final int TASKS = 100;
final CountDownLatch done = new CountDownLatch(TASKS);
for (int k = 0; k < TASKS; ++k)
@@ -1935,6 +1932,8 @@
done.countDown();
}});
assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(e);
}
}
@@ -1946,22 +1945,21 @@
new ThreadPoolExecutor(2, 2,
1000, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- assertFalse(p.allowsCoreThreadTimeOut());
- }
+ assertFalse(p.allowsCoreThreadTimeOut());
+ joinPool(p);
}
/**
* allowCoreThreadTimeOut(true) causes idle threads to time out
*/
public void testAllowCoreThreadTimeOut_true() throws Exception {
- long keepAliveTime = timeoutMillis();
+ long coreThreadTimeOut = SHORT_DELAY_MS;
final ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 10,
- keepAliveTime, MILLISECONDS,
+ coreThreadTimeOut, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
p.allowCoreThreadTimeOut(true);
p.execute(new CheckedRunnable() {
public void realRun() {
@@ -1969,13 +1967,15 @@
assertEquals(1, p.getPoolSize());
}});
await(threadStarted);
- delay(keepAliveTime);
+ delay(coreThreadTimeOut);
long startTime = System.nanoTime();
while (p.getPoolSize() > 0
&& millisElapsedSince(startTime) < LONG_DELAY_MS)
Thread.yield();
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
assertEquals(0, p.getPoolSize());
+ } finally {
+ joinPool(p);
}
}
@@ -1983,21 +1983,23 @@
* allowCoreThreadTimeOut(false) causes idle threads not to time out
*/
public void testAllowCoreThreadTimeOut_false() throws Exception {
- long keepAliveTime = timeoutMillis();
+ long coreThreadTimeOut = SHORT_DELAY_MS;
final ThreadPoolExecutor p =
new ThreadPoolExecutor(2, 10,
- keepAliveTime, MILLISECONDS,
+ coreThreadTimeOut, MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
- try (PoolCleaner cleaner = cleaner(p)) {
- final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
p.allowCoreThreadTimeOut(false);
p.execute(new CheckedRunnable() {
public void realRun() throws InterruptedException {
threadStarted.countDown();
assertTrue(p.getPoolSize() >= 1);
}});
- delay(2 * keepAliveTime);
+ delay(2 * coreThreadTimeOut);
assertTrue(p.getPoolSize() >= 1);
+ } finally {
+ joinPool(p);
}
}
@@ -2013,10 +2015,9 @@
done.countDown();
}};
final ThreadPoolExecutor p =
- new ThreadPoolExecutor(1, 30,
- 60, SECONDS,
+ new ThreadPoolExecutor(1, 30, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue(30));
- try (PoolCleaner cleaner = cleaner(p)) {
+ try {
for (int i = 0; i < nTasks; ++i) {
for (;;) {
try {
@@ -2028,43 +2029,8 @@
}
// enough time to run all tasks
assertTrue(done.await(nTasks * SHORT_DELAY_MS, MILLISECONDS));
- }
- }
-
- /**
- * get(cancelled task) throws CancellationException
- */
- public void testGet_cancelled() throws Exception {
- final CountDownLatch done = new CountDownLatch(1);
- final ExecutorService e =
- new ThreadPoolExecutor(1, 1,
- LONG_DELAY_MS, MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- try (PoolCleaner cleaner = cleaner(e, done)) {
- final CountDownLatch blockerStarted = new CountDownLatch(1);
- final List<Future<?>> futures = new ArrayList<>();
- for (int i = 0; i < 2; i++) {
- Runnable r = new CheckedRunnable() { public void realRun()
- throws Throwable {
- blockerStarted.countDown();
- assertTrue(done.await(2 * LONG_DELAY_MS, MILLISECONDS));
- }};
- futures.add(e.submit(r));
- }
- await(blockerStarted);
- for (Future<?> future : futures) future.cancel(false);
- for (Future<?> future : futures) {
- try {
- future.get();
- shouldThrow();
- } catch (CancellationException success) {}
- try {
- future.get(LONG_DELAY_MS, MILLISECONDS);
- shouldThrow();
- } catch (CancellationException success) {}
- assertTrue(future.isCancelled());
- assertTrue(future.isDone());
- }
+ } finally {
+ joinPool(p);
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadTest.java b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
index e69b422..27f22ca 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
@@ -19,7 +19,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(ThreadTest.class);
+ // return new TestSuite(...);
// }
static class MyHandler implements Thread.UncaughtExceptionHandler {
@@ -57,7 +57,8 @@
// default uncaught exception handler installed by the framework.
//
// assertEquals(null, Thread.getDefaultUncaughtExceptionHandler());
- // failure due to SecurityException is OK.
+
+ // failure due to securityException is OK.
// Would be nice to explicitly test both ways, but cannot yet.
Thread.UncaughtExceptionHandler defaultHandler
= Thread.getDefaultUncaughtExceptionHandler();
diff --git a/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
index b21fa7d..2c9529b 100644
--- a/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
@@ -30,7 +30,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(TimeUnitTest.class);
+ // return new TestSuite(...);
// }
// (loops to 88888 check increments at all time divisions.)
@@ -433,8 +433,8 @@
* a deserialized serialized unit is the same instance
*/
public void testSerialization() throws Exception {
- for (TimeUnit x : TimeUnit.values())
- assertSame(x, serialClone(x));
+ TimeUnit x = MILLISECONDS;
+ assertSame(x, serialClone(x));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
index e445609..afc73de 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(TreeMapTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
index c3093f6..a935637 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
@@ -29,7 +29,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(TreeSetTest.class);
+ // return new TestSuite(...);
// }
static class MyReverseComparator implements Comparator {
@@ -50,7 +50,7 @@
private TreeSet<Integer> populatedSet(int n) {
TreeSet<Integer> q = new TreeSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
@@ -96,7 +96,8 @@
*/
public void testConstructor4() {
try {
- new TreeSet(Arrays.asList(new Integer[SIZE]));
+ Integer[] ints = new Integer[SIZE];
+ new TreeSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -105,10 +106,10 @@
* Initializing from Collection with some null elements throws NPE
*/
public void testConstructor5() {
- Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
new TreeSet(Arrays.asList(ints));
shouldThrow();
} catch (NullPointerException success) {}
@@ -137,7 +138,7 @@
for (int i = 0; i < SIZE; ++i)
ints[i] = new Integer(i);
q.addAll(Arrays.asList(ints));
- for (int i = SIZE - 1; i >= 0; --i)
+ for (int i = SIZE-1; i >= 0; --i)
assertEquals(ints[i], q.pollFirst());
}
@@ -161,7 +162,7 @@
public void testSize() {
TreeSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -241,7 +242,7 @@
public void testAddAll3() {
TreeSet q = new TreeSet();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
+ for (int i = 0; i < SIZE-1; ++i)
ints[i] = new Integer(i);
try {
q.addAll(Arrays.asList(ints));
@@ -256,7 +257,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1-i);
TreeSet q = new TreeSet();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -280,7 +281,7 @@
*/
public void testPollLast() {
TreeSet q = populatedSet(SIZE);
- for (int i = SIZE - 1; i >= 0; --i) {
+ for (int i = SIZE-1; i >= 0; --i) {
assertEquals(i, q.pollLast());
}
assertNull(q.pollFirst());
@@ -295,14 +296,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -361,7 +362,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -374,7 +375,7 @@
TreeSet q = populatedSet(SIZE);
TreeSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
@@ -908,18 +909,18 @@
else if (element > max)
return -1;
int result = bs.nextSetBit(element);
- return (result > max) ? -1 : result;
+ return result > max ? -1 : result;
}
int higherAscending(int element) {
return ceilingAscending(element + 1);
}
private int firstAscending() {
int result = ceilingAscending(min);
- return (result > max) ? -1 : result;
+ return result > max ? -1 : result;
}
private int lastAscending() {
int result = floorAscending(max);
- return (result < min) ? -1 : result;
+ return result < min ? -1 : result;
}
}
ReferenceSet rs = new ReferenceSet();
@@ -980,7 +981,7 @@
}
static boolean eq(Integer i, int j) {
- return (i == null) ? j == -1 : i == j;
+ return i == null ? j == -1 : i == j;
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
index 09b809e..18a9e37 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
@@ -27,7 +27,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(TreeSubMapTest.class);
+ // return new TestSuite(...);
// }
/**
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
index 31403be..5398c4e 100644
--- a/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
@@ -25,7 +25,7 @@
// main(suite(), args);
// }
// public static Test suite() {
- // return new TestSuite(TreeSubSetTest.class);
+ // return new TestSuite(...);
// }
static class MyReverseComparator implements Comparator {
@@ -42,7 +42,7 @@
TreeSet<Integer> q = new TreeSet<Integer>();
assertTrue(q.isEmpty());
- for (int i = n - 1; i >= 0; i -= 2)
+ for (int i = n-1; i >= 0; i -= 2)
assertTrue(q.add(new Integer(i)));
for (int i = (n & 1); i < n; i += 2)
assertTrue(q.add(new Integer(i)));
@@ -124,7 +124,7 @@
public void testSize() {
NavigableSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -203,8 +203,8 @@
public void testAddAll3() {
NavigableSet q = set0();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i + SIZE);
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
q.addAll(Arrays.asList(ints));
shouldThrow();
@@ -218,7 +218,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1- i);
NavigableSet q = set0();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -246,14 +246,14 @@
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertTrue(q.contains(i - 1));
+ assertTrue(q.contains(i-1));
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.contains(i));
assertTrue(q.remove(i));
assertFalse(q.contains(i));
- assertFalse(q.remove(i + 1));
- assertFalse(q.contains(i + 1));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
}
assertTrue(q.isEmpty());
}
@@ -312,7 +312,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -325,7 +325,7 @@
NavigableSet q = populatedSet(SIZE);
NavigableSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
@@ -620,7 +620,7 @@
public void testDescendingSize() {
NavigableSet q = populatedSet(SIZE);
for (int i = 0; i < SIZE; ++i) {
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
q.pollFirst();
}
for (int i = 0; i < SIZE; ++i) {
@@ -688,8 +688,8 @@
public void testDescendingAddAll3() {
NavigableSet q = dset0();
Integer[] ints = new Integer[SIZE];
- for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i + SIZE);
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
try {
q.addAll(Arrays.asList(ints));
shouldThrow();
@@ -703,7 +703,7 @@
Integer[] empty = new Integer[0];
Integer[] ints = new Integer[SIZE];
for (int i = 0; i < SIZE; ++i)
- ints[i] = new Integer(SIZE - 1 - i);
+ ints[i] = new Integer(SIZE-1- i);
NavigableSet q = dset0();
assertFalse(q.addAll(Arrays.asList(empty)));
assertTrue(q.addAll(Arrays.asList(ints)));
@@ -732,7 +732,7 @@
}
for (int i = 0; i < SIZE; i += 2) {
assertTrue(q.remove(new Integer(i)));
- assertFalse(q.remove(new Integer(i + 1)));
+ assertFalse(q.remove(new Integer(i+1)));
}
assertTrue(q.isEmpty());
}
@@ -791,7 +791,7 @@
assertTrue(changed);
assertTrue(q.containsAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
p.pollFirst();
}
}
@@ -804,7 +804,7 @@
NavigableSet q = populatedSet(SIZE);
NavigableSet p = populatedSet(i);
assertTrue(q.removeAll(p));
- assertEquals(SIZE - i, q.size());
+ assertEquals(SIZE-i, q.size());
for (int j = 0; j < i; ++j) {
Integer x = (Integer)(p.pollFirst());
assertFalse(q.contains(x));
diff --git a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index 213baf2..f444b29 100644
--- a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -6,12 +6,7 @@
package java.util.concurrent;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
/**
* Provides default implementations of {@link ExecutorService}
@@ -28,7 +23,7 @@
* <p><b>Extension example</b>. Here is a sketch of a class
* that customizes {@link ThreadPoolExecutor} to use
* a {@code CustomTask} class instead of the default {@code FutureTask}:
- * <pre> {@code
+ * <pre> {@code
* public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
*
* static class CustomTask<V> implements RunnableFuture<V> {...}
@@ -123,7 +118,7 @@
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
- ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
+ ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
@@ -156,7 +151,7 @@
else if (active == 0)
break;
else if (timed) {
- f = ecs.poll(nanos, NANOSECONDS);
+ f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
@@ -181,7 +176,8 @@
throw ee;
} finally {
- cancelAll(futures);
+ for (int i = 0, size = futures.size(); i < size; i++)
+ futures.get(i).cancel(true);
}
}
@@ -205,7 +201,8 @@
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
- ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+ ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
@@ -215,15 +212,19 @@
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
- try { f.get(); }
- catch (CancellationException ignore) {}
- catch (ExecutionException ignore) {}
+ try {
+ f.get();
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ }
}
}
+ done = true;
return futures;
- } catch (Throwable t) {
- cancelAll(futures);
- throw t;
+ } finally {
+ if (!done)
+ for (int i = 0, size = futures.size(); i < size; i++)
+ futures.get(i).cancel(true);
}
}
@@ -232,52 +233,47 @@
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
- final long nanos = unit.toNanos(timeout);
- final long deadline = System.nanoTime() + nanos;
- ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
- int j = 0;
- timedOut: try {
+ long nanos = unit.toNanos(timeout);
+ ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ boolean done = false;
+ try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
+ final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
- if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
- break timedOut;
execute((Runnable)futures.get(i));
+ nanos = deadline - System.nanoTime();
+ if (nanos <= 0L)
+ return futures;
}
- for (; j < size; j++) {
- Future<T> f = futures.get(j);
+ for (int i = 0; i < size; i++) {
+ Future<T> f = futures.get(i);
if (!f.isDone()) {
- try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
- catch (CancellationException ignore) {}
- catch (ExecutionException ignore) {}
- catch (TimeoutException timedOut) {
- break timedOut;
+ if (nanos <= 0L)
+ return futures;
+ try {
+ f.get(nanos, TimeUnit.NANOSECONDS);
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ } catch (TimeoutException toe) {
+ return futures;
}
+ nanos = deadline - System.nanoTime();
}
}
+ done = true;
return futures;
- } catch (Throwable t) {
- cancelAll(futures);
- throw t;
+ } finally {
+ if (!done)
+ for (int i = 0, size = futures.size(); i < size; i++)
+ futures.get(i).cancel(true);
}
- // Timed out before all the tasks could be completed; cancel remaining
- cancelAll(futures, j);
- return futures;
}
- private static <T> void cancelAll(ArrayList<Future<T>> futures) {
- cancelAll(futures, 0);
- }
-
- /** Cancels all futures with index at least j. */
- private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
- for (int size = futures.size(); j < size; j++)
- futures.get(j).cancel(true);
- }
}
diff --git a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index 3183c01..9dca1b3 100644
--- a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -7,14 +7,11 @@
package java.util.concurrent;
import java.lang.ref.WeakReference;
-import java.util.AbstractQueue;
import java.util.Arrays;
+import java.util.AbstractQueue;
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;
@@ -95,7 +92,7 @@
* are known not to be any. Allows queue operations to update
* iterator state.
*/
- transient Itrs itrs;
+ transient Itrs itrs = null;
// Internal helper methods
@@ -240,8 +237,10 @@
try {
int i = 0;
try {
- for (E e : c)
- items[i++] = Objects.requireNonNull(e);
+ for (E e : c) {
+ if (e == null) throw new NullPointerException();
+ items[i++] = e;
+ }
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
@@ -277,7 +276,7 @@
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- Objects.requireNonNull(e);
+ if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
try {
@@ -300,7 +299,7 @@
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
- Objects.requireNonNull(e);
+ if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
@@ -323,13 +322,13 @@
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
- Objects.requireNonNull(e);
+ if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -368,7 +367,7 @@
lock.lockInterruptibly();
try {
while (count == 0) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -585,7 +584,27 @@
}
public String toString() {
- return Helpers.collectionToString(this);
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ int k = count;
+ if (k == 0)
+ return "[]";
+
+ final Object[] items = this.items;
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (int i = takeIndex; ; ) {
+ Object e = items[i];
+ sb.append(e == this ? "(this Collection)" : e);
+ if (--k == 0)
+ return sb.append(']').toString();
+ sb.append(',').append(' ');
+ if (++i == items.length) i = 0;
+ }
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -593,12 +612,12 @@
* The queue will be empty after this call returns.
*/
public void clear() {
+ final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int k = count;
if (k > 0) {
- final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
@@ -634,7 +653,7 @@
* @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)
@@ -1314,27 +1333,4 @@
// }
}
- /**
- * Returns a {@link Spliterator} over the elements in this queue.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this queue
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return Spliterators.spliterator
- (this, (Spliterator.ORDERED |
- Spliterator.NONNULL |
- Spliterator.CONCURRENT));
- }
-
}
diff --git a/luni/src/main/java/java/util/concurrent/BlockingDeque.java b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
index b52f719..b1437cc 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -6,13 +6,7 @@
package java.util.concurrent;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-// BEGIN android-note
-// fixed framework docs link to "Collection#optional"
-// END android-note
+import java.util.*;
/**
* A {@link Deque} that additionally supports blocking operations that wait
@@ -28,6 +22,7 @@
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of BlockingDeque methods</caption>
* <tr>
@@ -103,6 +98,7 @@
* {@code BlockingQueue} interface are precisely equivalent to
* {@code BlockingDeque} methods as indicated in the following table:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
* <tr>
@@ -173,7 +169,7 @@
*
* @since 1.6
* @author Doug Lea
- * @param <E> the type of elements held in this deque
+ * @param <E> the type of elements held in this collection
*/
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
/*
@@ -379,9 +375,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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean removeFirstOccurrence(Object o);
@@ -397,9 +393,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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean removeLastOccurrence(Object o);
@@ -574,9 +570,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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -589,18 +585,18 @@
* @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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
- boolean contains(Object o);
+ public boolean contains(Object o);
/**
* Returns the number of elements in this deque.
*
* @return the number of elements in this deque
*/
- int size();
+ public int size();
/**
* Returns an iterator over the elements in this deque in proper sequence.
diff --git a/luni/src/main/java/java/util/concurrent/BlockingQueue.java b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
index 2a56179..33d83b7 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -10,8 +10,7 @@
import java.util.Queue;
// BEGIN android-note
-// removed link to collections framework docs from header
-// fixed framework docs link to "Collection#optional"
+// removed link to collections framework docs
// END android-note
/**
@@ -29,6 +28,7 @@
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of BlockingQueue methods</caption>
* <tr>
@@ -103,7 +103,7 @@
* Usage example, based on a typical producer-consumer scenario.
* Note that a {@code BlockingQueue} can safely be used with multiple
* producers and multiple consumers.
- * <pre> {@code
+ * <pre> {@code
* class Producer implements Runnable {
* private final BlockingQueue queue;
* Producer(BlockingQueue q) { queue = q; }
@@ -147,7 +147,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public interface BlockingQueue<E> extends Queue<E> {
/**
@@ -275,9 +275,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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -290,11 +290,11 @@
* @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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
- boolean contains(Object o);
+ public boolean contains(Object o);
/**
* Removes all available elements from this queue and adds them
diff --git a/luni/src/main/java/java/util/concurrent/Callable.java b/luni/src/main/java/java/util/concurrent/Callable.java
index a22ec50..a3b3883 100644
--- a/luni/src/main/java/java/util/concurrent/Callable.java
+++ b/luni/src/main/java/java/util/concurrent/Callable.java
@@ -25,7 +25,6 @@
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
-@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
diff --git a/luni/src/main/java/java/util/concurrent/CompletableFuture.java b/luni/src/main/java/java/util/concurrent/CompletableFuture.java
deleted file mode 100644
index bcb6ed5..0000000
--- a/luni/src/main/java/java/util/concurrent/CompletableFuture.java
+++ /dev/null
@@ -1,2770 +0,0 @@
-/*
- * 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.util.concurrent.locks.LockSupport;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-/**
- * A {@link Future} that may be explicitly completed (setting its
- * value and status), and may be used as a {@link CompletionStage},
- * supporting dependent functions and actions that trigger upon its
- * completion.
- *
- * <p>When two or more threads attempt to
- * {@link #complete complete},
- * {@link #completeExceptionally completeExceptionally}, or
- * {@link #cancel cancel}
- * a CompletableFuture, only one of them succeeds.
- *
- * <p>In addition to these and related methods for directly
- * manipulating status and results, CompletableFuture implements
- * interface {@link CompletionStage} with the following policies: <ul>
- *
- * <li>Actions supplied for dependent completions of
- * <em>non-async</em> methods may be performed by the thread that
- * completes the current CompletableFuture, or by any other caller of
- * a completion method.
- *
- * <li>All <em>async</em> methods without an explicit Executor
- * argument are performed using the {@link ForkJoinPool#commonPool()}
- * (unless it does not support a parallelism level of at least two, in
- * which case, a new Thread is created to run each task). This may be
- * overridden for non-static methods in subclasses by defining method
- * {@link #defaultExecutor()}. To simplify monitoring, debugging,
- * and tracking, all generated asynchronous tasks are instances of the
- * marker interface {@link AsynchronousCompletionTask}. Operations
- * with time-delays can use adapter methods defined in this class, for
- * example: {@code supplyAsync(supplier, delayedExecutor(timeout,
- * timeUnit))}. To support methods with delays and timeouts, this
- * class maintains at most one daemon thread for triggering and
- * cancelling actions, not for running them.
- *
- * <li>All CompletionStage methods are implemented independently of
- * other public methods, so the behavior of one method is not impacted
- * by overrides of others in subclasses.
- *
- * <li>All CompletionStage methods return CompletableFutures. To
- * restrict usages to only those methods defined in interface
- * CompletionStage, use method {@link #minimalCompletionStage}. Or to
- * ensure only that clients do not themselves modify a future, use
- * method {@link #copy}.
- * </ul>
- *
- * <p>CompletableFuture also implements {@link Future} with the following
- * policies: <ul>
- *
- * <li>Since (unlike {@link FutureTask}) this class has no direct
- * control over the computation that causes it to be completed,
- * cancellation is treated as just another form of exceptional
- * completion. Method {@link #cancel cancel} has the same effect as
- * {@code completeExceptionally(new CancellationException())}. Method
- * {@link #isCompletedExceptionally} can be used to determine if a
- * CompletableFuture completed in any exceptional fashion.
- *
- * <li>In case of exceptional completion with a CompletionException,
- * methods {@link #get()} and {@link #get(long, TimeUnit)} throw an
- * {@link ExecutionException} with the same cause as held in the
- * corresponding CompletionException. To simplify usage in most
- * contexts, this class also defines methods {@link #join()} and
- * {@link #getNow} that instead throw the CompletionException directly
- * in these cases.
- * </ul>
- *
- * <p>Arguments used to pass a completion result (that is, for
- * parameters of type {@code T}) for methods accepting them may be
- * null, but passing a null value for any other parameter will result
- * in a {@link NullPointerException} being thrown.
- *
- * <p>Subclasses of this class should normally override the "virtual
- * constructor" method {@link #newIncompleteFuture}, which establishes
- * the concrete type returned by CompletionStage methods. For example,
- * here is a class that substitutes a different default Executor and
- * disables the {@code obtrude} methods:
- *
- * <pre> {@code
- * class MyCompletableFuture<T> extends CompletableFuture<T> {
- * static final Executor myExecutor = ...;
- * public MyCompletableFuture() { }
- * public <U> CompletableFuture<U> newIncompleteFuture() {
- * return new MyCompletableFuture<U>(); }
- * public Executor defaultExecutor() {
- * return myExecutor; }
- * public void obtrudeValue(T value) {
- * throw new UnsupportedOperationException(); }
- * public void obtrudeException(Throwable ex) {
- * throw new UnsupportedOperationException(); }
- * }}</pre>
- *
- * @author Doug Lea
- * @since 1.8
- * @param <T> The result type returned by this future's {@code join}
- * and {@code get} methods
- */
-public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
-
- /*
- * Overview:
- *
- * A CompletableFuture may have dependent completion actions,
- * collected in a linked stack. It atomically completes by CASing
- * a result field, and then pops off and runs those actions. This
- * applies across normal vs exceptional outcomes, sync vs async
- * actions, binary triggers, and various forms of completions.
- *
- * 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 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.
- *
- * Support for each kind of CompletionStage relies on a separate
- * class, along with two CompletableFuture methods:
- *
- * * A Completion class with name X corresponding to function,
- * prefaced with "Uni", "Bi", or "Or". Each class contains
- * fields for source(s), actions, and dependent. They are
- * boringly similar, differing from others only with respect to
- * underlying functional forms. We do this so that users don't
- * encounter layers of adapters in common usages.
- *
- * * Boolean CompletableFuture method x(...) (for example
- * 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
- * complete.
- *
- * * Completion method tryFire(int mode) invokes the associated x
- * 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.
- *
- * * CompletableFuture method xStage(...) is called from a public
- * stage method of CompletableFuture x. It screens user
- * arguments and invokes and/or creates the stage object. If
- * 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.
- *
- * Method postComplete is called upon completion unless the target
- * is guaranteed not to be observable (i.e., not yet returned or
- * linked). Multiple threads can call postComplete, which
- * atomically pops each dependent action, and tries to trigger it
- * via method tryFire, in NESTED mode. Triggering can propagate
- * recursively, so NESTED mode returns its completed dependent (if
- * one exists) for further processing by its caller (see method
- * postFire).
- *
- * Blocking methods get() and join() rely on Signaller Completions
- * that wake up waiting threads. The mechanics are similar to
- * Treiber stack wait-nodes used in FutureTask, Phaser, and
- * SynchronousQueue. See their internal documentation for
- * algorithmic details.
- *
- * Without precautions, CompletableFutures would be prone to
- * garbage accumulation as chains of Completions build up, each
- * 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 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 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;
- lazySetNext(c, h);
- return U.compareAndSwapObject(this, STACK, h, c);
- }
-
- /** Unconditionally pushes c onto stack, retrying if necessary. */
- final void pushStack(Completion c) {
- do {} while (!tryPushStack(c));
- }
-
- /* ------------- Encoding and decoding outcomes -------------- */
-
- static final class AltResult { // See above
- final Throwable ex; // null only for NIL
- AltResult(Throwable x) { this.ex = x; }
- }
-
- /** The encoding of the null value. */
- static final AltResult NIL = new AltResult(null);
-
- /** Completes with the null value, unless already completed. */
- final boolean completeNull() {
- return U.compareAndSwapObject(this, RESULT, null,
- NIL);
- }
-
- /** Returns the encoding of the given non-exceptional value. */
- final Object encodeValue(T t) {
- return (t == null) ? NIL : t;
- }
-
- /** Completes with a non-exceptional result, unless already completed. */
- final boolean completeValue(T t) {
- return U.compareAndSwapObject(this, RESULT, null,
- (t == null) ? NIL : t);
- }
-
- /**
- * Returns the encoding of the given (non-null) exception as a
- * wrapped CompletionException unless it is one already.
- */
- static AltResult encodeThrowable(Throwable x) {
- return new AltResult((x instanceof CompletionException) ? x :
- new CompletionException(x));
- }
-
- /** Completes with an exceptional result, unless already completed. */
- final boolean completeThrowable(Throwable x) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeThrowable(x));
- }
-
- /**
- * Returns the encoding of the given (non-null) exception as a
- * wrapped CompletionException unless it is one already. May
- * return the given Object r (which must have been the result of a
- * source future) if it is equivalent, i.e. if this is a simple
- * relay of an existing CompletionException.
- */
- static Object encodeThrowable(Throwable x, Object r) {
- if (!(x instanceof CompletionException))
- x = new CompletionException(x);
- else if (r instanceof AltResult && x == ((AltResult)r).ex)
- return r;
- return new AltResult(x);
- }
-
- /**
- * Completes with the given (non-null) exceptional result as a
- * wrapped CompletionException unless it is one already, unless
- * already completed. May complete with the given Object r
- * (which must have been the result of a source future) if it is
- * equivalent, i.e. if this is a simple propagation of an
- * existing CompletionException.
- */
- final boolean completeThrowable(Throwable x, Object r) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeThrowable(x, r));
- }
-
- /**
- * Returns the encoding of the given arguments: if the exception
- * is non-null, encodes as AltResult. Otherwise uses the given
- * value, boxed as NIL if null.
- */
- Object encodeOutcome(T t, Throwable x) {
- return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
- }
-
- /**
- * Returns the encoding of a copied outcome; if exceptional,
- * rewraps as a CompletionException, else returns argument.
- */
- static Object encodeRelay(Object r) {
- Throwable x;
- return (((r instanceof AltResult) &&
- (x = ((AltResult)r).ex) != null &&
- !(x instanceof CompletionException)) ?
- new AltResult(new CompletionException(x)) : r);
- }
-
- /**
- * Completes with r or a copy of r, unless already completed.
- * If exceptional, r is first coerced to a CompletionException.
- */
- final boolean completeRelay(Object r) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeRelay(r));
- }
-
- /**
- * Reports result using Future.get conventions.
- */
- private static <T> T reportGet(Object r)
- throws InterruptedException, ExecutionException {
- if (r == null) // by convention below, null means interrupted
- throw new InterruptedException();
- if (r instanceof AltResult) {
- Throwable x, cause;
- if ((x = ((AltResult)r).ex) == null)
- return null;
- if (x instanceof CancellationException)
- throw (CancellationException)x;
- if ((x instanceof CompletionException) &&
- (cause = x.getCause()) != null)
- x = cause;
- throw new ExecutionException(x);
- }
- @SuppressWarnings("unchecked") T t = (T) r;
- return t;
- }
-
- /**
- * Decodes outcome to return result or throw unchecked exception.
- */
- private static <T> T reportJoin(Object r) {
- if (r instanceof AltResult) {
- Throwable x;
- if ((x = ((AltResult)r).ex) == null)
- return null;
- if (x instanceof CancellationException)
- throw (CancellationException)x;
- if (x instanceof CompletionException)
- throw (CompletionException)x;
- throw new CompletionException(x);
- }
- @SuppressWarnings("unchecked") T t = (T) r;
- return t;
- }
-
- /* ------------- Async task preliminaries -------------- */
-
- /**
- * A marker interface identifying asynchronous tasks produced by
- * {@code async} methods. This may be useful for monitoring,
- * debugging, and tracking asynchronous activities.
- *
- * @since 1.8
- */
- public static interface AsynchronousCompletionTask {
- }
-
- private static final boolean USE_COMMON_POOL =
- (ForkJoinPool.getCommonPoolParallelism() > 1);
-
- /**
- * Default executor -- ForkJoinPool.commonPool() unless it cannot
- * support parallelism.
- */
- private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
- ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
-
- /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
- static final class ThreadPerTaskExecutor implements Executor {
- public void execute(Runnable r) { new Thread(r).start(); }
- }
-
- /**
- * Null-checks user executor argument, and translates uses of
- * commonPool to ASYNC_POOL in case parallelism disabled.
- */
- static Executor screenExecutor(Executor e) {
- if (!USE_COMMON_POOL && e == ForkJoinPool.commonPool())
- return ASYNC_POOL;
- if (e == null) throw new NullPointerException();
- return e;
- }
-
- // Modes for Completion.tryFire. Signedness matters.
- static final int SYNC = 0;
- 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")
- abstract static class Completion extends ForkJoinTask<Void>
- implements Runnable, AsynchronousCompletionTask {
- volatile Completion next; // Treiber stack link
-
- /**
- * Performs completion action if triggered, returning a
- * dependent that may need propagation, if one exists.
- *
- * @param mode SYNC, ASYNC, or NESTED
- */
- abstract CompletableFuture<?> tryFire(int mode);
-
- /** Returns true if possibly still triggerable. Used by cleanStack. */
- abstract boolean isLive();
-
- public final void run() { tryFire(ASYNC); }
- public final boolean exec() { tryFire(ASYNC); return false; }
- public final Void getRawResult() { return null; }
- 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.
- */
- final void postComplete() {
- /*
- * On each step, variable f holds current dependents to pop
- * and run. It is extended along only one path at a time,
- * pushing others to avoid unbounded recursion.
- */
- CompletableFuture<?> f = this; Completion h;
- while ((h = f.stack) != null ||
- (f != this && (h = (f = this).stack) != null)) {
- CompletableFuture<?> d; Completion t;
- if (f.casStack(h, t = h.next)) {
- if (t != null) {
- if (f != this) {
- pushStack(h);
- continue;
- }
- h.next = null; // detach
- }
- f = (d = h.tryFire(NESTED)) == null ? this : d;
- }
- }
- }
-
- /** Traverses stack and unlinks dead Completions. */
- final void cleanStack() {
- for (Completion p = null, q = stack; q != null;) {
- Completion s = q.next;
- if (q.isLive()) {
- p = q;
- q = s;
- }
- else if (p == null) {
- casStack(q, s);
- q = stack;
- }
- else {
- p.next = s;
- if (p.isLive())
- q = s;
- else {
- p = null; // restart
- q = stack;
- }
- }
- }
- }
-
- /* ------------- One-input Completions -------------- */
-
- /** A Completion with a source, dependent, and executor. */
- @SuppressWarnings("serial")
- abstract static class UniCompletion<T,V> extends Completion {
- Executor executor; // executor to use (null if none)
- CompletableFuture<V> dep; // the dependent to complete
- CompletableFuture<T> src; // source for action
-
- UniCompletion(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src) {
- this.executor = executor; this.dep = dep; this.src = src;
- }
-
- /**
- * Returns true if action can be run. Call only when known to
- * be triggerable. Uses FJ tag bit to ensure that only one
- * thread claims ownership. If async, starts as task -- a
- * later call to tryFire will run action.
- */
- final boolean claim() {
- Executor e = executor;
- if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
- if (e == null)
- return true;
- executor = null; // disable
- e.execute(this);
- }
- return false;
- }
-
- final boolean isLive() { return dep != null; }
- }
-
- /** Pushes the given completion (if it exists) unless done. */
- final void push(UniCompletion<?,?> c) {
- if (c != null) {
- 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.
- */
- final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
- if (a != null && a.stack != null) {
- if (mode < 0 || a.result == null)
- a.cleanStack();
- else
- a.postComplete();
- }
- if (result != null && stack != null) {
- if (mode < 0)
- return this;
- else
- postComplete();
- }
- return null;
- }
-
- @SuppressWarnings("serial")
- static final class UniApply<T,V> extends UniCompletion<T,V> {
- Function<? super T,? extends V> fn;
- UniApply(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src,
- Function<? super T,? extends V> fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<V> tryFire(int mode) {
- CompletableFuture<V> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniApply(a = src, fn, mode > 0 ? null : this))
- return null;
- 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();
- CompletableFuture<V> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class UniAccept<T> extends UniCompletion<T,Void> {
- Consumer<? super T> fn;
- UniAccept(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src, Consumer<? super T> fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniAccept(a = src, fn, mode > 0 ? null : this))
- return null;
- 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();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class UniRun<T> extends UniCompletion<T,Void> {
- Runnable fn;
- UniRun(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src, Runnable fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniRun(a = src, fn, mode > 0 ? null : this))
- return null;
- dep = null; src = null; fn = null;
- return d.postFire(a, mode);
- }
- }
-
- 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> uniRunStage(Executor e, Runnable f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class UniWhenComplete<T> extends UniCompletion<T,T> {
- BiConsumer<? super T, ? super Throwable> fn;
- UniWhenComplete(Executor executor, CompletableFuture<T> dep,
- CompletableFuture<T> src,
- BiConsumer<? super T, ? super Throwable> fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<T> tryFire(int mode) {
- CompletableFuture<T> d; CompletableFuture<T> a;
- 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(CompletableFuture<T> a,
- BiConsumer<? super T,? super Throwable> f,
- UniWhenComplete<T> c) {
- 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())
- return false;
- if (r instanceof AltResult) {
- x = ((AltResult)r).ex;
- t = null;
- } else {
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- f.accept(t, x);
- if (x == null) {
- internalComplete(r);
- return true;
- }
- } catch (Throwable ex) {
- if (x == null)
- x = ex;
- else if (x != ex)
- x.addSuppressed(ex);
- }
- completeThrowable(x, r);
- }
- return true;
- }
-
- private CompletableFuture<T> uniWhenCompleteStage(
- Executor e, BiConsumer<? super T, ? super Throwable> f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<T> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class UniHandle<T,V> extends UniCompletion<T,V> {
- BiFunction<? super T, Throwable, ? extends V> fn;
- UniHandle(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src,
- BiFunction<? super T, Throwable, ? extends V> fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<V> tryFire(int mode) {
- CompletableFuture<V> d; CompletableFuture<T> a;
- 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(CompletableFuture<S> a,
- BiFunction<? super S, Throwable, ? extends T> f,
- UniHandle<S,T> c) {
- 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())
- return false;
- if (r instanceof AltResult) {
- x = ((AltResult)r).ex;
- s = null;
- } else {
- x = null;
- @SuppressWarnings("unchecked") S ss = (S) r;
- s = ss;
- }
- completeValue(f.apply(s, x));
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
- private <V> CompletableFuture<V> uniHandleStage(
- Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<V> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class UniExceptionally<T> extends UniCompletion<T,T> {
- Function<? super Throwable, ? extends T> fn;
- UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
- Function<? super Throwable, ? extends T> fn) {
- super(null, dep, src); this.fn = fn;
- }
- final CompletableFuture<T> tryFire(int mode) { // never ASYNC
- // assert mode != ASYNC;
- CompletableFuture<T> d; CompletableFuture<T> a;
- 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(CompletableFuture<T> a,
- Function<? super Throwable, ? extends T> f,
- UniExceptionally<T> c) {
- 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) {
- if (c != null && !c.claim())
- return false;
- completeValue(f.apply(x));
- } else
- internalComplete(r);
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
- private CompletableFuture<T> uniExceptionallyStage(
- Function<Throwable, ? extends T> f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<T> d = newIncompleteFuture();
- 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<T> extends UniCompletion<T,T> { // for Compose
- UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
- super(null, dep, src);
- }
- final CompletableFuture<T> tryFire(int mode) {
- CompletableFuture<T> d; CompletableFuture<T> a;
- if ((d = dep) == null || !d.uniRelay(a = src))
- return null;
- src = null; dep = null;
- return d.postFire(a, mode);
- }
- }
-
- final boolean uniRelay(CompletableFuture<T> a) {
- Object r;
- 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;
- }
-
- private MinimalStage<T> uniAsMinimalStage() {
- Object r;
- if ((r = result) != null)
- return new MinimalStage<T>(encodeRelay(r));
- MinimalStage<T> d = new MinimalStage<T>();
- UniRelay<T> c = new UniRelay<T>(d, this);
- push(c);
- c.tryFire(SYNC);
- return d;
- }
-
- @SuppressWarnings("serial")
- static final class UniCompose<T,V> extends UniCompletion<T,V> {
- Function<? super T, ? extends CompletionStage<V>> fn;
- UniCompose(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src,
- Function<? super T, ? extends CompletionStage<V>> fn) {
- super(executor, dep, src); this.fn = fn;
- }
- final CompletableFuture<V> tryFire(int mode) {
- CompletableFuture<V> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniCompose(a = src, fn, mode > 0 ? null : this))
- return null;
- 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();
- Object r, s; Throwable x;
- 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);
- return d;
- }
- r = null;
- }
- try {
- @SuppressWarnings("unchecked") T t = (T) r;
- CompletableFuture<V> g = f.apply(t).toCompletableFuture();
- if ((s = g.result) != null)
- d.completeRelay(s);
- else {
- 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;
- }
- }
- UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
- return d;
- }
-
- /* ------------- Two-input Completions -------------- */
-
- /** A Completion for an action with two sources */
- @SuppressWarnings("serial")
- abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
- CompletableFuture<U> snd; // second source for action
- BiCompletion(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src, CompletableFuture<U> snd) {
- super(executor, dep, src); this.snd = snd;
- }
- }
-
- /** A Completion delegating to a BiCompletion */
- @SuppressWarnings("serial")
- static final class CoCompletion extends Completion {
- BiCompletion<?,?,?> base;
- CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
- final CompletableFuture<?> tryFire(int mode) {
- BiCompletion<?,?,?> c; CompletableFuture<?> d;
- if ((c = base) == null || (d = c.tryFire(mode)) == null)
- return null;
- base = null; // detach
- return d;
- }
- final boolean isLive() {
- BiCompletion<?,?,?> c;
- return (c = base) != null && c.dep != null;
- }
- }
-
- /** Pushes completion to this and b unless both done. */
- final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
- if (c != null) {
- 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
- }
- }
- }
-
- /** Post-processing after successful BiCompletion tryFire. */
- final CompletableFuture<T> postFire(CompletableFuture<?> a,
- CompletableFuture<?> b, int mode) {
- if (b != null && b.stack != null) { // clean second source
- if (mode < 0 || b.result == null)
- b.cleanStack();
- else
- b.postComplete();
- }
- return postFire(a, mode);
- }
-
- @SuppressWarnings("serial")
- static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
- BiFunction<? super T,? super U,? extends V> fn;
- BiApply(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src, CompletableFuture<U> snd,
- BiFunction<? super T,? super U,? extends V> fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<V> tryFire(int mode) {
- CompletableFuture<V> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- 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(CompletableFuture<R> a,
- CompletableFuture<S> b,
- BiFunction<? super R,? super S,? extends T> f,
- BiApply<R,S,T> c) {
- 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) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- if (s instanceof AltResult) {
- if ((x = ((AltResult)s).ex) != null) {
- completeThrowable(x, s);
- break tryComplete;
- }
- s = null;
- }
- try {
- if (c != null && !c.claim())
- return false;
- @SuppressWarnings("unchecked") R rr = (R) r;
- @SuppressWarnings("unchecked") S ss = (S) s;
- completeValue(f.apply(rr, ss));
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
- private <U,V> CompletableFuture<V> biApplyStage(
- Executor e, CompletionStage<U> o,
- BiFunction<? super T,? super U,? extends V> f) {
- CompletableFuture<U> b;
- if (f == null || (b = o.toCompletableFuture()) == null)
- throw new NullPointerException();
- CompletableFuture<V> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
- BiConsumer<? super T,? super U> fn;
- BiAccept(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src, CompletableFuture<U> snd,
- BiConsumer<? super T,? super U> fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- 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(CompletableFuture<R> a,
- CompletableFuture<S> b,
- BiConsumer<? super R,? super S> f,
- BiAccept<R,S> c) {
- 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) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- if (s instanceof AltResult) {
- if ((x = ((AltResult)s).ex) != null) {
- completeThrowable(x, s);
- break tryComplete;
- }
- s = null;
- }
- try {
- if (c != null && !c.claim())
- return false;
- @SuppressWarnings("unchecked") R rr = (R) r;
- @SuppressWarnings("unchecked") S ss = (S) s;
- f.accept(rr, ss);
- completeNull();
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
- private <U> CompletableFuture<Void> biAcceptStage(
- Executor e, CompletionStage<U> o,
- BiConsumer<? super T,? super U> f) {
- CompletableFuture<U> b;
- if (f == null || (b = o.toCompletableFuture()) == null)
- throw new NullPointerException();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- 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,
- Runnable fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- 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(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)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())
- return false;
- f.run();
- completeNull();
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
- private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
- Runnable f) {
- CompletableFuture<?> b;
- if (f == null || (b = o.toCompletableFuture()) == null)
- throw new NullPointerException();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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) {
- super(null, dep, src, snd);
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- if ((d = dep) == null || !d.biRelay(a = src, b = snd))
- return null;
- 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) {
- CompletableFuture<Void> d = new CompletableFuture<Void>();
- if (lo > hi) // empty
- d.result = NIL;
- else {
- 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 (!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. */
- final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
- if (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
- }
- }
- }
-
- @SuppressWarnings("serial")
- 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,
- Function<? super T,? extends V> fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<V> tryFire(int mode) {
- CompletableFuture<V> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orApply(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 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) {
- CompletableFuture<U> b;
- if (f == null || (b = o.toCompletableFuture()) == null)
- throw new NullPointerException();
- CompletableFuture<V> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- 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,
- Consumer<? super T> fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orAccept(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 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();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- 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,
- Runnable fn) {
- super(executor, dep, src, snd); this.fn = fn;
- }
- final CompletableFuture<Void> tryFire(int mode) {
- CompletableFuture<Void> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orRun(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 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();
- CompletableFuture<Void> d = newIncompleteFuture();
- 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;
- }
-
- @SuppressWarnings("serial")
- 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) {
- CompletableFuture<Object> d;
- 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")
- static final class AsyncSupply<T> extends ForkJoinTask<Void>
- implements Runnable, AsynchronousCompletionTask {
- CompletableFuture<T> dep; Supplier<? extends T> fn;
- AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) {
- this.dep = dep; this.fn = fn;
- }
-
- public final Void getRawResult() { return null; }
- public final void setRawResult(Void v) {}
- public final boolean exec() { run(); return true; }
-
- public void run() {
- CompletableFuture<T> d; Supplier<? extends T> f;
- if ((d = dep) != null && (f = fn) != null) {
- dep = null; fn = null;
- if (d.result == null) {
- try {
- d.completeValue(f.get());
- } catch (Throwable ex) {
- d.completeThrowable(ex);
- }
- }
- d.postComplete();
- }
- }
- }
-
- static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
- Supplier<U> f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<U> d = new CompletableFuture<U>();
- e.execute(new AsyncSupply<U>(d, f));
- return d;
- }
-
- @SuppressWarnings("serial")
- static final class AsyncRun extends ForkJoinTask<Void>
- implements Runnable, AsynchronousCompletionTask {
- CompletableFuture<Void> dep; Runnable fn;
- AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
- this.dep = dep; this.fn = fn;
- }
-
- public final Void getRawResult() { return null; }
- public final void setRawResult(Void v) {}
- public final boolean exec() { run(); return true; }
-
- public void run() {
- CompletableFuture<Void> d; Runnable f;
- if ((d = dep) != null && (f = fn) != null) {
- dep = null; fn = null;
- if (d.result == null) {
- try {
- f.run();
- d.completeNull();
- } catch (Throwable ex) {
- d.completeThrowable(ex);
- }
- }
- d.postComplete();
- }
- }
- }
-
- static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
- if (f == null) throw new NullPointerException();
- CompletableFuture<Void> d = new CompletableFuture<Void>();
- e.execute(new AsyncRun(d, f));
- return d;
- }
-
- /* ------------- Signallers -------------- */
-
- /**
- * Completion for recording and releasing a waiting thread. This
- * class implements ManagedBlocker to avoid starvation when
- * blocking actions pile up in ForkJoinPools.
- */
- @SuppressWarnings("serial")
- static final class Signaller extends Completion
- implements ForkJoinPool.ManagedBlocker {
- long nanos; // remaining wait time if timed
- final long deadline; // non-zero if timed
- final boolean interruptible;
- boolean interrupted;
- volatile Thread thread;
-
- Signaller(boolean interruptible, long nanos, long deadline) {
- this.thread = Thread.currentThread();
- this.interruptible = interruptible;
- this.nanos = nanos;
- this.deadline = deadline;
- }
- final CompletableFuture<?> tryFire(int ignore) {
- Thread w; // no need to atomically claim
- if ((w = thread) != null) {
- thread = null;
- LockSupport.unpark(w);
- }
- return null;
- }
- public boolean isReleasable() {
- if (Thread.interrupted())
- interrupted = true;
- return ((interrupted && interruptible) ||
- (deadline != 0L &&
- (nanos <= 0L ||
- (nanos = deadline - System.nanoTime()) <= 0L)) ||
- thread == null);
- }
- public boolean block() {
- while (!isReleasable()) {
- if (deadline == 0L)
- LockSupport.park(this);
- else
- LockSupport.parkNanos(this, nanos);
- }
- return true;
- }
- final boolean isLive() { return thread != null; }
- }
-
- /**
- * Returns raw result after waiting, or null if interruptible and
- * interrupted.
- */
- private Object waitingGet(boolean interruptible) {
- Signaller q = null;
- boolean queued = false;
- int spins = SPINS;
- Object r;
- while ((r = result) == null) {
- 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 {
- try {
- ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ie) { // currently cannot happen
- q.interrupted = true;
- }
- if (q.interrupted && interruptible)
- break;
- }
- }
- if (q != null) {
- q.thread = null;
- if (q.interrupted) {
- if (interruptible)
- cleanStack();
- else
- Thread.currentThread().interrupt();
- }
- }
- if (r != null)
- postComplete();
- return r;
- }
-
- /**
- * Returns raw result after waiting, or null if interrupted, or
- * throws TimeoutException on timeout.
- */
- private Object timedGet(long nanos) throws TimeoutException {
- if (Thread.interrupted())
- return null;
- if (nanos > 0L) {
- long d = System.nanoTime() + nanos;
- long deadline = (d == 0L) ? 1L : d; // avoid 0
- Signaller q = null;
- boolean queued = false;
- Object r;
- while ((r = result) == null) { // similar to untimed, without spins
- if (q == null)
- q = new Signaller(true, nanos, deadline);
- else if (!queued)
- queued = tryPushStack(q);
- else if (q.nanos <= 0L)
- break;
- else {
- try {
- ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ie) {
- q.interrupted = true;
- }
- if (q.interrupted)
- break;
- }
- }
- if (q != null)
- q.thread = null;
- if (r != null)
- postComplete();
- else
- cleanStack();
- if (r != null || (q != null && q.interrupted))
- return r;
- }
- throw new TimeoutException();
- }
-
- /* ------------- public methods -------------- */
-
- /**
- * Creates a new incomplete CompletableFuture.
- */
- public CompletableFuture() {
- }
-
- /**
- * Creates a new complete CompletableFuture with given encoded result.
- */
- CompletableFuture(Object r) {
- this.result = r;
- }
-
- /**
- * Returns a new CompletableFuture that is asynchronously completed
- * by a task running in the {@link ForkJoinPool#commonPool()} with
- * the value obtained by calling the given Supplier.
- *
- * @param supplier a function returning the value to be used
- * to complete the returned CompletableFuture
- * @param <U> the function's return type
- * @return the new CompletableFuture
- */
- public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
- return asyncSupplyStage(ASYNC_POOL, supplier);
- }
-
- /**
- * Returns a new CompletableFuture that is asynchronously completed
- * by a task running in the given executor with the value obtained
- * by calling the given Supplier.
- *
- * @param supplier a function returning the value to be used
- * to complete the returned CompletableFuture
- * @param executor the executor to use for asynchronous execution
- * @param <U> the function's return type
- * @return the new CompletableFuture
- */
- public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
- Executor executor) {
- return asyncSupplyStage(screenExecutor(executor), supplier);
- }
-
- /**
- * Returns a new CompletableFuture that is asynchronously completed
- * by a task running in the {@link ForkJoinPool#commonPool()} after
- * it runs the given action.
- *
- * @param runnable the action to run before completing the
- * returned CompletableFuture
- * @return the new CompletableFuture
- */
- public static CompletableFuture<Void> runAsync(Runnable runnable) {
- return asyncRunStage(ASYNC_POOL, runnable);
- }
-
- /**
- * Returns a new CompletableFuture that is asynchronously completed
- * by a task running in the given executor after it runs the given
- * action.
- *
- * @param runnable the action to run before completing the
- * returned CompletableFuture
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletableFuture
- */
- public static CompletableFuture<Void> runAsync(Runnable runnable,
- Executor executor) {
- return asyncRunStage(screenExecutor(executor), runnable);
- }
-
- /**
- * Returns a new CompletableFuture that is already completed with
- * the given value.
- *
- * @param value the value
- * @param <U> the type of the value
- * @return the completed CompletableFuture
- */
- public static <U> CompletableFuture<U> completedFuture(U value) {
- return new CompletableFuture<U>((value == null) ? NIL : value);
- }
-
- /**
- * Returns {@code true} if completed in any fashion: normally,
- * exceptionally, or via cancellation.
- *
- * @return {@code true} if completed
- */
- public boolean isDone() {
- return result != null;
- }
-
- /**
- * Waits if necessary for this future to complete, and then
- * returns its result.
- *
- * @return the result value
- * @throws CancellationException if this future was cancelled
- * @throws ExecutionException if this future completed exceptionally
- * @throws InterruptedException if the current thread was interrupted
- * while waiting
- */
- public T get() throws InterruptedException, ExecutionException {
- Object r;
- return reportGet((r = result) == null ? waitingGet(true) : r);
- }
-
- /**
- * Waits if necessary for at most the given time for this future
- * to complete, and then returns its result, if available.
- *
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @return the result value
- * @throws CancellationException if this future was cancelled
- * @throws ExecutionException if this future completed exceptionally
- * @throws InterruptedException if the current thread was interrupted
- * while waiting
- * @throws TimeoutException if the wait timed out
- */
- public T get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException {
- Object r;
- long nanos = unit.toNanos(timeout);
- return reportGet((r = result) == null ? timedGet(nanos) : r);
- }
-
- /**
- * Returns the result value when complete, or throws an
- * (unchecked) exception if completed exceptionally. To better
- * conform with the use of common functional forms, if a
- * computation involved in the completion of this
- * CompletableFuture threw an exception, this method throws an
- * (unchecked) {@link CompletionException} with the underlying
- * exception as its cause.
- *
- * @return the result value
- * @throws CancellationException if the computation was cancelled
- * @throws CompletionException if this future completed
- * exceptionally or a completion computation threw an exception
- */
- public T join() {
- Object r;
- return reportJoin((r = result) == null ? waitingGet(false) : r);
- }
-
- /**
- * Returns the result value (or throws any encountered exception)
- * if completed, else returns the given valueIfAbsent.
- *
- * @param valueIfAbsent the value to return if not completed
- * @return the result value, if completed, else the given valueIfAbsent
- * @throws CancellationException if the computation was cancelled
- * @throws CompletionException if this future completed
- * exceptionally or a completion computation threw an exception
- */
- public T getNow(T valueIfAbsent) {
- Object r;
- return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
- }
-
- /**
- * If not already completed, sets the value returned by {@link
- * #get()} and related methods to the given value.
- *
- * @param value the result value
- * @return {@code true} if this invocation caused this CompletableFuture
- * to transition to a completed state, else {@code false}
- */
- public boolean complete(T value) {
- boolean triggered = completeValue(value);
- postComplete();
- return triggered;
- }
-
- /**
- * If not already completed, causes invocations of {@link #get()}
- * and related methods to throw the given exception.
- *
- * @param ex the exception
- * @return {@code true} if this invocation caused this CompletableFuture
- * to transition to a completed state, else {@code false}
- */
- public boolean completeExceptionally(Throwable ex) {
- if (ex == null) throw new NullPointerException();
- boolean triggered = internalComplete(new AltResult(ex));
- postComplete();
- return triggered;
- }
-
- public <U> CompletableFuture<U> thenApply(
- Function<? super T,? extends U> fn) {
- return uniApplyStage(null, fn);
- }
-
- public <U> CompletableFuture<U> thenApplyAsync(
- Function<? super T,? extends U> fn) {
- return uniApplyStage(defaultExecutor(), fn);
- }
-
- public <U> CompletableFuture<U> thenApplyAsync(
- Function<? super T,? extends U> fn, Executor executor) {
- return uniApplyStage(screenExecutor(executor), fn);
- }
-
- public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
- return uniAcceptStage(null, action);
- }
-
- public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
- return uniAcceptStage(defaultExecutor(), action);
- }
-
- public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
- Executor executor) {
- return uniAcceptStage(screenExecutor(executor), action);
- }
-
- public CompletableFuture<Void> thenRun(Runnable action) {
- return uniRunStage(null, action);
- }
-
- public CompletableFuture<Void> thenRunAsync(Runnable action) {
- return uniRunStage(defaultExecutor(), action);
- }
-
- public CompletableFuture<Void> thenRunAsync(Runnable action,
- Executor executor) {
- return uniRunStage(screenExecutor(executor), action);
- }
-
- public <U,V> CompletableFuture<V> thenCombine(
- CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return biApplyStage(null, other, fn);
- }
-
- public <U,V> CompletableFuture<V> thenCombineAsync(
- CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return biApplyStage(defaultExecutor(), other, fn);
- }
-
- public <U,V> CompletableFuture<V> thenCombineAsync(
- CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
- return biApplyStage(screenExecutor(executor), other, fn);
- }
-
- public <U> CompletableFuture<Void> thenAcceptBoth(
- CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return biAcceptStage(null, other, action);
- }
-
- public <U> CompletableFuture<Void> thenAcceptBothAsync(
- CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return biAcceptStage(defaultExecutor(), other, action);
- }
-
- public <U> CompletableFuture<Void> thenAcceptBothAsync(
- CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action, Executor executor) {
- return biAcceptStage(screenExecutor(executor), other, action);
- }
-
- public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
- Runnable action) {
- return biRunStage(null, other, action);
- }
-
- public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
- Runnable action) {
- return biRunStage(defaultExecutor(), other, action);
- }
-
- public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- return biRunStage(screenExecutor(executor), other, action);
- }
-
- public <U> CompletableFuture<U> applyToEither(
- CompletionStage<? extends T> other, Function<? super T, U> fn) {
- return orApplyStage(null, other, fn);
- }
-
- public <U> CompletableFuture<U> applyToEitherAsync(
- CompletionStage<? extends T> other, Function<? super T, U> fn) {
- return orApplyStage(defaultExecutor(), other, fn);
- }
-
- public <U> CompletableFuture<U> applyToEitherAsync(
- CompletionStage<? extends T> other, Function<? super T, U> fn,
- Executor executor) {
- return orApplyStage(screenExecutor(executor), other, fn);
- }
-
- public CompletableFuture<Void> acceptEither(
- CompletionStage<? extends T> other, Consumer<? super T> action) {
- return orAcceptStage(null, other, action);
- }
-
- public CompletableFuture<Void> acceptEitherAsync(
- CompletionStage<? extends T> other, Consumer<? super T> action) {
- return orAcceptStage(defaultExecutor(), other, action);
- }
-
- public CompletableFuture<Void> acceptEitherAsync(
- CompletionStage<? extends T> other, Consumer<? super T> action,
- Executor executor) {
- return orAcceptStage(screenExecutor(executor), other, action);
- }
-
- public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
- Runnable action) {
- return orRunStage(null, other, action);
- }
-
- public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
- Runnable action) {
- return orRunStage(defaultExecutor(), other, action);
- }
-
- public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- return orRunStage(screenExecutor(executor), other, action);
- }
-
- public <U> CompletableFuture<U> thenCompose(
- Function<? super T, ? extends CompletionStage<U>> fn) {
- return uniComposeStage(null, fn);
- }
-
- public <U> CompletableFuture<U> thenComposeAsync(
- Function<? super T, ? extends CompletionStage<U>> fn) {
- return uniComposeStage(defaultExecutor(), fn);
- }
-
- public <U> CompletableFuture<U> thenComposeAsync(
- Function<? super T, ? extends CompletionStage<U>> fn,
- Executor executor) {
- return uniComposeStage(screenExecutor(executor), fn);
- }
-
- public CompletableFuture<T> whenComplete(
- BiConsumer<? super T, ? super Throwable> action) {
- return uniWhenCompleteStage(null, action);
- }
-
- public CompletableFuture<T> whenCompleteAsync(
- BiConsumer<? super T, ? super Throwable> action) {
- return uniWhenCompleteStage(defaultExecutor(), action);
- }
-
- public CompletableFuture<T> whenCompleteAsync(
- BiConsumer<? super T, ? super Throwable> action, Executor executor) {
- return uniWhenCompleteStage(screenExecutor(executor), action);
- }
-
- public <U> CompletableFuture<U> handle(
- BiFunction<? super T, Throwable, ? extends U> fn) {
- return uniHandleStage(null, fn);
- }
-
- public <U> CompletableFuture<U> handleAsync(
- BiFunction<? super T, Throwable, ? extends U> fn) {
- return uniHandleStage(defaultExecutor(), fn);
- }
-
- public <U> CompletableFuture<U> handleAsync(
- BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
- return uniHandleStage(screenExecutor(executor), fn);
- }
-
- /**
- * Returns this CompletableFuture.
- *
- * @return this CompletableFuture
- */
- public CompletableFuture<T> toCompletableFuture() {
- return this;
- }
-
- // not in interface CompletionStage
-
- /**
- * Returns a new CompletableFuture that is completed when this
- * CompletableFuture completes, with the result of the given
- * function of the exception triggering this CompletableFuture's
- * completion when it completes exceptionally; otherwise, if this
- * CompletableFuture completes normally, then the returned
- * CompletableFuture also completes normally with the same value.
- * Note: More flexible versions of this functionality are
- * available using methods {@code whenComplete} and {@code handle}.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletableFuture if this CompletableFuture completed
- * exceptionally
- * @return the new CompletableFuture
- */
- public CompletableFuture<T> exceptionally(
- Function<Throwable, ? extends T> fn) {
- return uniExceptionallyStage(fn);
- }
-
-
- /* ------------- Arbitrary-arity constructions -------------- */
-
- /**
- * Returns a new CompletableFuture that is completed when all of
- * the given CompletableFutures complete. If any of the given
- * CompletableFutures complete exceptionally, then the returned
- * CompletableFuture also does so, with a CompletionException
- * holding this exception as its cause. Otherwise, the results,
- * if any, of the given CompletableFutures are not reflected in
- * the returned CompletableFuture, but may be obtained by
- * inspecting them individually. If no CompletableFutures are
- * provided, returns a CompletableFuture completed with the value
- * {@code null}.
- *
- * <p>Among the applications of this method is to await completion
- * of a set of independent CompletableFutures before continuing a
- * program, as in: {@code CompletableFuture.allOf(c1, c2,
- * c3).join();}.
- *
- * @param cfs the CompletableFutures
- * @return a new CompletableFuture that is completed when all of the
- * given CompletableFutures complete
- * @throws NullPointerException if the array or any of its elements are
- * {@code null}
- */
- public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
- return andTree(cfs, 0, cfs.length - 1);
- }
-
- /**
- * Returns a new CompletableFuture that is completed when any of
- * the given CompletableFutures complete, with the same result.
- * Otherwise, if it completed exceptionally, the returned
- * CompletableFuture also does so, with a CompletionException
- * holding this exception as its cause. If no CompletableFutures
- * are provided, returns an incomplete CompletableFuture.
- *
- * @param cfs the CompletableFutures
- * @return a new CompletableFuture that is completed with the
- * result or exception of any of the given CompletableFutures when
- * one completes
- * @throws NullPointerException if the array or any of its elements are
- * {@code null}
- */
- public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
- return orTree(cfs, 0, cfs.length - 1);
- }
-
- /* ------------- Control and status methods -------------- */
-
- /**
- * If not already completed, completes this CompletableFuture with
- * a {@link CancellationException}. Dependent CompletableFutures
- * that have not already completed will also complete
- * exceptionally, with a {@link CompletionException} caused by
- * this {@code CancellationException}.
- *
- * @param mayInterruptIfRunning this value has no effect in this
- * implementation because interrupts are not used to control
- * processing.
- *
- * @return {@code true} if this task is now cancelled
- */
- public boolean cancel(boolean mayInterruptIfRunning) {
- boolean cancelled = (result == null) &&
- internalComplete(new AltResult(new CancellationException()));
- postComplete();
- return cancelled || isCancelled();
- }
-
- /**
- * Returns {@code true} if this CompletableFuture was cancelled
- * before it completed normally.
- *
- * @return {@code true} if this CompletableFuture was cancelled
- * before it completed normally
- */
- public boolean isCancelled() {
- Object r;
- return ((r = result) instanceof AltResult) &&
- (((AltResult)r).ex instanceof CancellationException);
- }
-
- /**
- * Returns {@code true} if this CompletableFuture completed
- * exceptionally, in any way. Possible causes include
- * cancellation, explicit invocation of {@code
- * completeExceptionally}, and abrupt termination of a
- * CompletionStage action.
- *
- * @return {@code true} if this CompletableFuture completed
- * exceptionally
- */
- public boolean isCompletedExceptionally() {
- Object r;
- return ((r = result) instanceof AltResult) && r != NIL;
- }
-
- /**
- * Forcibly sets or resets the value subsequently returned by
- * method {@link #get()} and related methods, whether or not
- * already completed. This method is designed for use only in
- * error recovery actions, and even in such situations may result
- * in ongoing dependent completions using established versus
- * overwritten outcomes.
- *
- * @param value the completion value
- */
- public void obtrudeValue(T value) {
- result = (value == null) ? NIL : value;
- postComplete();
- }
-
- /**
- * Forcibly causes subsequent invocations of method {@link #get()}
- * and related methods to throw the given exception, whether or
- * not already completed. This method is designed for use only in
- * error recovery actions, and even in such situations may result
- * in ongoing dependent completions using established versus
- * overwritten outcomes.
- *
- * @param ex the exception
- * @throws NullPointerException if the exception is null
- */
- public void obtrudeException(Throwable ex) {
- if (ex == null) throw new NullPointerException();
- result = new AltResult(ex);
- postComplete();
- }
-
- /**
- * Returns the estimated number of CompletableFutures whose
- * completions are awaiting completion of this CompletableFuture.
- * This method is designed for use in monitoring system state, not
- * for synchronization control.
- *
- * @return the number of dependent CompletableFutures
- */
- public int getNumberOfDependents() {
- int count = 0;
- for (Completion p = stack; p != null; p = p.next)
- ++count;
- return count;
- }
-
- /**
- * Returns a string identifying this CompletableFuture, as well as
- * its completion state. The state, in brackets, contains the
- * String {@code "Completed Normally"} or the String {@code
- * "Completed Exceptionally"}, or the String {@code "Not
- * completed"} followed by the number of CompletableFutures
- * dependent upon its completion, if any.
- *
- * @return a string identifying this CompletableFuture, as well as its state
- */
- public String toString() {
- Object r = result;
- int count = 0; // avoid call to getNumberOfDependents in case disabled
- 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]" :
- "[Completed normally]"));
- }
-
- // jdk9 additions
-
- /**
- * Returns a new incomplete CompletableFuture of the type to be
- * returned by a CompletionStage method. Subclasses should
- * normally override this method to return an instance of the same
- * class as this CompletableFuture. The default implementation
- * returns an instance of class CompletableFuture.
- *
- * @param <U> the type of the value
- * @return a new CompletableFuture
- * @since 9
- */
- public <U> CompletableFuture<U> newIncompleteFuture() {
- return new CompletableFuture<U>();
- }
-
- /**
- * Returns the default Executor used for async methods that do not
- * specify an Executor. This class uses the {@link
- * ForkJoinPool#commonPool()} if it supports more than one
- * parallel thread, or else an Executor using one thread per async
- * task. This method may be overridden in subclasses to return
- * an Executor that provides at least one independent thread.
- *
- * @return the executor
- * @since 9
- */
- public Executor defaultExecutor() {
- return ASYNC_POOL;
- }
-
- /**
- * Returns a new CompletableFuture that is completed normally with
- * the same value as this CompletableFuture when it completes
- * normally. If this CompletableFuture completes exceptionally,
- * then the returned CompletableFuture completes exceptionally
- * with a CompletionException with this exception as cause. The
- * behavior is equivalent to {@code thenApply(x -> x)}. This
- * method may be useful as a form of "defensive copying", to
- * prevent clients from completing, while still being able to
- * arrange dependent actions.
- *
- * @return the new CompletableFuture
- * @since 9
- */
- public CompletableFuture<T> copy() {
- return uniCopyStage();
- }
-
- /**
- * Returns a new CompletionStage that is completed normally with
- * the same value as this CompletableFuture when it completes
- * normally, and cannot be independently completed or otherwise
- * used in ways not defined by the methods of interface {@link
- * CompletionStage}. If this CompletableFuture completes
- * exceptionally, then the returned CompletionStage completes
- * exceptionally with a CompletionException with this exception as
- * cause.
- *
- * @return the new CompletionStage
- * @since 9
- */
- public CompletionStage<T> minimalCompletionStage() {
- return uniAsMinimalStage();
- }
-
- /**
- * Completes this CompletableFuture with the result of
- * the given Supplier function invoked from an asynchronous
- * task using the given executor.
- *
- * @param supplier a function returning the value to be used
- * to complete this CompletableFuture
- * @param executor the executor to use for asynchronous execution
- * @return this CompletableFuture
- * @since 9
- */
- public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
- Executor executor) {
- if (supplier == null || executor == null)
- throw new NullPointerException();
- executor.execute(new AsyncSupply<T>(this, supplier));
- return this;
- }
-
- /**
- * Completes this CompletableFuture with the result of the given
- * Supplier function invoked from an asynchronous task using the
- * default executor.
- *
- * @param supplier a function returning the value to be used
- * to complete this CompletableFuture
- * @return this CompletableFuture
- * @since 9
- */
- public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) {
- return completeAsync(supplier, defaultExecutor());
- }
-
- /**
- * Exceptionally completes this CompletableFuture with
- * a {@link TimeoutException} if not otherwise completed
- * before the given timeout.
- *
- * @param timeout how long to wait before completing exceptionally
- * with a TimeoutException, in units of {@code unit}
- * @param unit a {@code TimeUnit} determining how to interpret the
- * {@code timeout} parameter
- * @return this CompletableFuture
- * @since 9
- */
- public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) {
- if (unit == null)
- throw new NullPointerException();
- if (result == null)
- whenComplete(new Canceller(Delayer.delay(new Timeout(this),
- timeout, unit)));
- return this;
- }
-
- /**
- * Completes this CompletableFuture with the given value if not
- * otherwise completed before the given timeout.
- *
- * @param value the value to use upon timeout
- * @param timeout how long to wait before completing normally
- * with the given value, in units of {@code unit}
- * @param unit a {@code TimeUnit} determining how to interpret the
- * {@code timeout} parameter
- * @return this CompletableFuture
- * @since 9
- */
- public CompletableFuture<T> completeOnTimeout(T value, long timeout,
- TimeUnit unit) {
- if (unit == null)
- throw new NullPointerException();
- if (result == null)
- whenComplete(new Canceller(Delayer.delay(
- new DelayedCompleter<T>(this, value),
- timeout, unit)));
- return this;
- }
-
- /**
- * Returns a new Executor that submits a task to the given base
- * executor after the given delay (or no delay if non-positive).
- * Each delay commences upon invocation of the returned executor's
- * {@code execute} method.
- *
- * @param delay how long to delay, in units of {@code unit}
- * @param unit a {@code TimeUnit} determining how to interpret the
- * {@code delay} parameter
- * @param executor the base executor
- * @return the new delayed executor
- * @since 9
- */
- public static Executor delayedExecutor(long delay, TimeUnit unit,
- Executor executor) {
- if (unit == null || executor == null)
- throw new NullPointerException();
- return new DelayedExecutor(delay, unit, executor);
- }
-
- /**
- * Returns a new Executor that submits a task to the default
- * executor after the given delay (or no delay if non-positive).
- * Each delay commences upon invocation of the returned executor's
- * {@code execute} method.
- *
- * @param delay how long to delay, in units of {@code unit}
- * @param unit a {@code TimeUnit} determining how to interpret the
- * {@code delay} parameter
- * @return the new delayed executor
- * @since 9
- */
- public static Executor delayedExecutor(long delay, TimeUnit unit) {
- if (unit == null)
- throw new NullPointerException();
- return new DelayedExecutor(delay, unit, ASYNC_POOL);
- }
-
- /**
- * Returns a new CompletionStage that is already completed with
- * the given value and supports only those methods in
- * interface {@link CompletionStage}.
- *
- * @param value the value
- * @param <U> the type of the value
- * @return the completed CompletionStage
- * @since 9
- */
- public static <U> CompletionStage<U> completedStage(U value) {
- return new MinimalStage<U>((value == null) ? NIL : value);
- }
-
- /**
- * Returns a new CompletableFuture that is already completed
- * exceptionally with the given exception.
- *
- * @param ex the exception
- * @param <U> the type of the value
- * @return the exceptionally completed CompletableFuture
- * @since 9
- */
- public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
- if (ex == null) throw new NullPointerException();
- return new CompletableFuture<U>(new AltResult(ex));
- }
-
- /**
- * Returns a new CompletionStage that is already completed
- * exceptionally with the given exception and supports only those
- * methods in interface {@link CompletionStage}.
- *
- * @param ex the exception
- * @param <U> the type of the value
- * @return the exceptionally completed CompletionStage
- * @since 9
- */
- public static <U> CompletionStage<U> failedStage(Throwable ex) {
- if (ex == null) throw new NullPointerException();
- return new MinimalStage<U>(new AltResult(ex));
- }
-
- /**
- * Singleton delay scheduler, used only for starting and
- * cancelling tasks.
- */
- static final class Delayer {
- static ScheduledFuture<?> delay(Runnable command, long delay,
- TimeUnit unit) {
- return delayer.schedule(command, delay, unit);
- }
-
- static final class DaemonThreadFactory implements ThreadFactory {
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setDaemon(true);
- t.setName("CompletableFutureDelayScheduler");
- return t;
- }
- }
-
- static final ScheduledThreadPoolExecutor delayer;
- static {
- (delayer = new ScheduledThreadPoolExecutor(
- 1, new DaemonThreadFactory())).
- setRemoveOnCancelPolicy(true);
- }
- }
-
- // Little class-ified lambdas to better support monitoring
-
- static final class DelayedExecutor implements Executor {
- final long delay;
- final TimeUnit unit;
- final Executor executor;
- DelayedExecutor(long delay, TimeUnit unit, Executor executor) {
- this.delay = delay; this.unit = unit; this.executor = executor;
- }
- public void execute(Runnable r) {
- Delayer.delay(new TaskSubmitter(executor, r), delay, unit);
- }
- }
-
- /** Action to submit user task */
- static final class TaskSubmitter implements Runnable {
- final Executor executor;
- final Runnable action;
- TaskSubmitter(Executor executor, Runnable action) {
- this.executor = executor;
- this.action = action;
- }
- public void run() { executor.execute(action); }
- }
-
- /** Action to completeExceptionally on timeout */
- static final class Timeout implements Runnable {
- final CompletableFuture<?> f;
- Timeout(CompletableFuture<?> f) { this.f = f; }
- public void run() {
- if (f != null && !f.isDone())
- f.completeExceptionally(new TimeoutException());
- }
- }
-
- /** Action to complete on timeout */
- static final class DelayedCompleter<U> implements Runnable {
- final CompletableFuture<U> f;
- final U u;
- DelayedCompleter(CompletableFuture<U> f, U u) { this.f = f; this.u = u; }
- public void run() {
- if (f != null)
- f.complete(u);
- }
- }
-
- /** Action to cancel unneeded timeouts */
- static final class Canceller implements BiConsumer<Object, Throwable> {
- final Future<?> f;
- Canceller(Future<?> f) { this.f = f; }
- public void accept(Object ignore, Throwable ex) {
- if (ex == null && f != null && !f.isDone())
- f.cancel(false);
- }
- }
-
- /**
- * A subclass that just throws UOE for most non-CompletionStage methods.
- */
- static final class MinimalStage<T> extends CompletableFuture<T> {
- MinimalStage() { }
- MinimalStage(Object r) { super(r); }
- @Override public <U> CompletableFuture<U> newIncompleteFuture() {
- return new MinimalStage<U>(); }
- @Override public T get() {
- throw new UnsupportedOperationException(); }
- @Override public T get(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException(); }
- @Override public T getNow(T valueIfAbsent) {
- throw new UnsupportedOperationException(); }
- @Override public T join() {
- throw new UnsupportedOperationException(); }
- @Override public boolean complete(T value) {
- throw new UnsupportedOperationException(); }
- @Override public boolean completeExceptionally(Throwable ex) {
- throw new UnsupportedOperationException(); }
- @Override public boolean cancel(boolean mayInterruptIfRunning) {
- throw new UnsupportedOperationException(); }
- @Override public void obtrudeValue(T value) {
- throw new UnsupportedOperationException(); }
- @Override public void obtrudeException(Throwable ex) {
- throw new UnsupportedOperationException(); }
- @Override public boolean isDone() {
- throw new UnsupportedOperationException(); }
- @Override public boolean isCancelled() {
- throw new UnsupportedOperationException(); }
- @Override public boolean isCompletedExceptionally() {
- throw new UnsupportedOperationException(); }
- @Override public int getNumberOfDependents() {
- throw new UnsupportedOperationException(); }
- @Override public CompletableFuture<T> completeAsync
- (Supplier<? extends T> supplier, Executor executor) {
- throw new UnsupportedOperationException(); }
- @Override public CompletableFuture<T> completeAsync
- (Supplier<? extends T> supplier) {
- throw new UnsupportedOperationException(); }
- @Override public CompletableFuture<T> orTimeout
- (long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException(); }
- @Override public CompletableFuture<T> completeOnTimeout
- (T value, long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException(); }
- }
-
- // 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 {
- 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 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;
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/CompletionException.java b/luni/src/main/java/java/util/concurrent/CompletionException.java
deleted file mode 100644
index 9b905d2..0000000
--- a/luni/src/main/java/java/util/concurrent/CompletionException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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;
-
-/**
- * Exception thrown when an error or other exception is encountered
- * in the course of completing a result or task.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class CompletionException extends RuntimeException {
- private static final long serialVersionUID = 7830266012832686185L;
-
- /**
- * Constructs a {@code CompletionException} with no detail message.
- * The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- */
- protected CompletionException() { }
-
- /**
- * Constructs a {@code CompletionException} with the specified detail
- * message. The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- *
- * @param message the detail message
- */
- protected CompletionException(String message) {
- super(message);
- }
-
- /**
- * Constructs a {@code CompletionException} with the specified detail
- * message and cause.
- *
- * @param message the detail message
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public CompletionException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a {@code CompletionException} with the specified cause.
- * The detail message is set to {@code (cause == null ? null :
- * cause.toString())} (which typically contains the class and
- * detail message of {@code cause}).
- *
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public CompletionException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/CompletionStage.java b/luni/src/main/java/java/util/concurrent/CompletionStage.java
deleted file mode 100644
index ccb1aa4..0000000
--- a/luni/src/main/java/java/util/concurrent/CompletionStage.java
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * 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.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * A stage of a possibly asynchronous computation, that performs an
- * action or computes a value when another CompletionStage completes.
- * A stage completes upon termination of its computation, but this may
- * in turn trigger other dependent stages. The functionality defined
- * in this interface takes only a few basic forms, which expand out to
- * a larger set of methods to capture a range of usage styles:
- *
- * <ul>
- *
- * <li>The computation performed by a stage may be expressed as a
- * Function, Consumer, or Runnable (using methods with names including
- * <em>apply</em>, <em>accept</em>, or <em>run</em>, respectively)
- * depending on whether it requires arguments and/or produces results.
- * For example:
- * <pre> {@code
- * stage.thenApply(x -> square(x))
- * .thenAccept(x -> System.out.print(x))
- * .thenRun(() -> System.out.println());}</pre>
- *
- * An additional form (<em>compose</em>) allows the construction of
- * computation pipelines from functions returning completion stages.
- *
- * <p>Any argument to a stage's computation is the outcome of a
- * triggering stage's computation.
- *
- * <li>One stage's execution may be triggered by completion of a
- * single stage, or both of two stages, or either of two stages.
- * Dependencies on a single stage are arranged using methods with
- * prefix <em>then</em>. Those triggered by completion of
- * <em>both</em> of two stages may <em>combine</em> their results or
- * effects, using correspondingly named methods. Those triggered by
- * <em>either</em> of two stages make no guarantees about which of the
- * results or effects are used for the dependent stage's computation.
- *
- * <li>Dependencies among stages control the triggering of
- * computations, but do not otherwise guarantee any particular
- * ordering. Additionally, execution of a new stage's computations may
- * be arranged in any of three ways: default execution, default
- * asynchronous execution (using methods with suffix <em>async</em>
- * that employ the stage's default asynchronous execution facility),
- * or custom (via a supplied {@link Executor}). The execution
- * properties of default and async modes are specified by
- * CompletionStage implementations, not this interface. Methods with
- * explicit Executor arguments may have arbitrary execution
- * properties, and might not even support concurrent execution, but
- * are arranged for processing in a way that accommodates asynchrony.
- *
- * <li>Two method forms ({@link #handle handle} and {@link
- * #whenComplete whenComplete}) support unconditional computation
- * whether the triggering stage completed normally or exceptionally.
- * Method {@link #exceptionally exceptionally} supports computation
- * only when the triggering stage completes exceptionally, computing a
- * replacement result, similarly to the java {@code catch} keyword.
- * In all other cases, if a stage's computation terminates abruptly
- * with an (unchecked) exception or error, then all dependent stages
- * requiring its completion complete exceptionally as well, with a
- * {@link CompletionException} holding the exception as its cause. If
- * a stage is dependent on <em>both</em> of two stages, and both
- * complete exceptionally, then the CompletionException may correspond
- * to either one of these exceptions. If a stage is dependent on
- * <em>either</em> of two others, and only one of them completes
- * exceptionally, no guarantees are made about whether the dependent
- * stage completes normally or exceptionally. In the case of method
- * {@code whenComplete}, when the supplied action itself encounters an
- * exception, then the stage completes exceptionally with this
- * exception unless the source stage also completed exceptionally, in
- * which case the exceptional completion from the source stage is
- * given preference and propagated to the dependent stage.
- *
- * </ul>
- *
- * <p>All methods adhere to the above triggering, execution, and
- * exceptional completion specifications (which are not repeated in
- * individual method specifications). Additionally, while arguments
- * used to pass a completion result (that is, for parameters of type
- * {@code T}) for methods accepting them may be null, passing a null
- * value for any other parameter will result in a {@link
- * NullPointerException} being thrown.
- *
- * <p>Method form {@link #handle handle} is the most general way of
- * creating a continuation stage, unconditionally performing a
- * computation that is given both the result and exception (if any) of
- * the triggering CompletionStage, and computing an arbitrary result.
- * Method {@link #whenComplete whenComplete} is similar, but preserves
- * the result of the triggering stage instead of computing a new one.
- * Because a stage's normal result may be {@code null}, both methods
- * should have a computation structured thus:
- *
- * <pre>{@code (result, exception) -> {
- * if (exception == null) {
- * // triggering stage completed normally
- * } else {
- * // triggering stage completed exceptionally
- * }
- * }}</pre>
- *
- * <p>This interface does not define methods for initially creating,
- * forcibly completing normally or exceptionally, probing completion
- * status or results, or awaiting completion of a stage.
- * Implementations of CompletionStage may provide means of achieving
- * such effects, as appropriate. Method {@link #toCompletableFuture}
- * enables interoperability among different implementations of this
- * interface by providing a common conversion type.
- *
- * @author Doug Lea
- * @since 1.8
- */
-public interface CompletionStage<T> {
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed with this stage's result as the argument
- * to the supplied function.
- *
- * <p>This method is analogous to
- * {@link java.util.Optional#map Optional.map} and
- * TODO(streams): make a link to java.util.stream.Stream#map Stream.map.
- *
- * <p>See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed using this stage's default asynchronous
- * execution facility, with this stage's result as the argument to
- * the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenApplyAsync
- (Function<? super T,? extends U> fn);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed using the supplied Executor, with this
- * stage's result as the argument to the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenApplyAsync
- (Function<? super T,? extends U> fn,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed with this stage's result as the argument
- * to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenAccept(Consumer<? super T> action);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed using this stage's default asynchronous
- * execution facility, with this stage's result as the argument to
- * the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, is executed using the supplied Executor, with this
- * stage's result as the argument to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
- Executor executor);
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, executes the given action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenRun(Runnable action);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, executes the given action using this stage's default
- * asynchronous execution facility.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenRunAsync(Runnable action);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * normally, executes the given action using the supplied Executor.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<Void> thenRunAsync(Runnable action,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed with the two
- * results as arguments to the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the type of the other CompletionStage's result
- * @param <V> the function's return type
- * @return the new CompletionStage
- */
- public <U,V> CompletionStage<V> thenCombine
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed using this
- * stage's default asynchronous execution facility, with the two
- * results as arguments to the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the type of the other CompletionStage's result
- * @param <V> the function's return type
- * @return the new CompletionStage
- */
- public <U,V> CompletionStage<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed using the
- * supplied executor, with the two results as arguments to the
- * supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the type of the other CompletionStage's result
- * @param <V> the function's return type
- * @return the new CompletionStage
- */
- public <U,V> CompletionStage<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed with the two
- * results as arguments to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param <U> the type of the other CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<Void> thenAcceptBoth
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed using this
- * stage's default asynchronous execution facility, with the two
- * results as arguments to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param <U> the type of the other CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, is executed using the
- * supplied executor, with the two results as arguments to the
- * supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the type of the other CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, executes the given action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,
- Runnable action);
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, executes the given action
- * using this stage's default asynchronous execution facility.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
- Runnable action);
-
- /**
- * Returns a new CompletionStage that, when this and the other
- * given stage both complete normally, executes the given action
- * using the supplied executor.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
- Runnable action,
- Executor executor);
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed with the
- * corresponding result as argument to the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> applyToEither
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed using this
- * stage's default asynchronous execution facility, with the
- * corresponding result as argument to the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed using the
- * supplied executor, with the corresponding result as argument to
- * the supplied function.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed with the
- * corresponding result as argument to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> acceptEither
- (CompletionStage<? extends T> other,
- Consumer<? super T> action);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed using this
- * stage's default asynchronous execution facility, with the
- * corresponding result as argument to the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, is executed using the
- * supplied executor, with the corresponding result as argument to
- * the supplied action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, executes the given action.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterEither(CompletionStage<?> other,
- Runnable action);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, executes the given action
- * using this stage's default asynchronous execution facility.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action);
-
- /**
- * Returns a new CompletionStage that, when either this or the
- * other given stage complete normally, executes the given action
- * using the supplied executor.
- *
- * See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param other the other CompletionStage
- * @param action the action to perform before completing the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that is completed with the same
- * value as the CompletionStage returned by the given function.
- *
- * <p>When this stage completes normally, the given function is
- * invoked with this stage's result as the argument, returning
- * another CompletionStage. When that stage completes normally,
- * the CompletionStage returned by this method is completed with
- * the same value.
- *
- * <p>To ensure progress, the supplied function must arrange
- * eventual completion of its result.
- *
- * <p>This method is analogous to
- * {@link java.util.Optional#flatMap Optional.flatMap} and
- * TODO(streams): make a link to java.util.stream.Stream#flatMap Stream.flatMap.
- *
- * <p>See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute another CompletionStage
- * @param <U> the type of the returned CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenCompose
- (Function<? super T, ? extends CompletionStage<U>> fn);
-
- /**
- * Returns a new CompletionStage that is completed with the same
- * value as the CompletionStage returned by the given function,
- * executed using this stage's default asynchronous execution
- * facility.
- *
- * <p>When this stage completes normally, the given function is
- * invoked with this stage's result as the argument, returning
- * another CompletionStage. When that stage completes normally,
- * the CompletionStage returned by this method is completed with
- * the same value.
- *
- * <p>To ensure progress, the supplied function must arrange
- * eventual completion of its result.
- *
- * <p>See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute another CompletionStage
- * @param <U> the type of the returned CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn);
-
- /**
- * Returns a new CompletionStage that is completed with the same
- * value as the CompletionStage returned by the given function,
- * executed using the supplied Executor.
- *
- * <p>When this stage completes normally, the given function is
- * invoked with this stage's result as the argument, returning
- * another CompletionStage. When that stage completes normally,
- * the CompletionStage returned by this method is completed with
- * the same value.
- *
- * <p>To ensure progress, the supplied function must arrange
- * eventual completion of its result.
- *
- * <p>See the {@link CompletionStage} documentation for rules
- * covering exceptional completion.
- *
- * @param fn the function to use to compute another CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the type of the returned CompletionStage's result
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * either normally or exceptionally, is executed with this stage's
- * result and exception as arguments to the supplied function.
- *
- * <p>When this stage is complete, the given function is invoked
- * with the result (or {@code null} if none) and the exception (or
- * {@code null} if none) of this stage as arguments, and the
- * function's result is used to complete the returned stage.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> handle
- (BiFunction<? super T, Throwable, ? extends U> fn);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * either normally or exceptionally, is executed using this stage's
- * default asynchronous execution facility, with this stage's
- * result and exception as arguments to the supplied function.
- *
- * <p>When this stage is complete, the given function is invoked
- * with the result (or {@code null} if none) and the exception (or
- * {@code null} if none) of this stage as arguments, and the
- * function's result is used to complete the returned stage.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * either normally or exceptionally, is executed using the
- * supplied executor, with this stage's result and exception as
- * arguments to the supplied function.
- *
- * <p>When this stage is complete, the given function is invoked
- * with the result (or {@code null} if none) and the exception (or
- * {@code null} if none) of this stage as arguments, and the
- * function's result is used to complete the returned stage.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage
- * @param executor the executor to use for asynchronous execution
- * @param <U> the function's return type
- * @return the new CompletionStage
- */
- public <U> CompletionStage<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn,
- Executor executor);
-
- /**
- * Returns a new CompletionStage with the same result or exception as
- * this stage, that executes the given action when this stage completes.
- *
- * <p>When this stage is complete, the given action is invoked
- * with the result (or {@code null} if none) and the exception (or
- * {@code null} if none) of this stage as arguments. The returned
- * stage is completed when the action returns.
- *
- * <p>Unlike method {@link #handle handle},
- * this method is not designed to translate completion outcomes,
- * so the supplied action should not throw an exception. However,
- * if it does, the following rules apply: if this stage completed
- * normally but the supplied action throws an exception, then the
- * returned stage completes exceptionally with the supplied
- * action's exception. Or, if this stage completed exceptionally
- * and the supplied action throws an exception, then the returned
- * stage completes exceptionally with this stage's exception.
- *
- * @param action the action to perform
- * @return the new CompletionStage
- */
- public CompletionStage<T> whenComplete
- (BiConsumer<? super T, ? super Throwable> action);
-
- /**
- * Returns a new CompletionStage with the same result or exception as
- * this stage, that executes the given action using this stage's
- * default asynchronous execution facility when this stage completes.
- *
- * <p>When this stage is complete, the given action is invoked with the
- * result (or {@code null} if none) and the exception (or {@code null}
- * if none) of this stage as arguments. The returned stage is completed
- * when the action returns.
- *
- * <p>Unlike method {@link #handleAsync(BiFunction) handleAsync},
- * this method is not designed to translate completion outcomes,
- * so the supplied action should not throw an exception. However,
- * if it does, the following rules apply: If this stage completed
- * normally but the supplied action throws an exception, then the
- * returned stage completes exceptionally with the supplied
- * action's exception. Or, if this stage completed exceptionally
- * and the supplied action throws an exception, then the returned
- * stage completes exceptionally with this stage's exception.
- *
- * @param action the action to perform
- * @return the new CompletionStage
- */
- public CompletionStage<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action);
-
- /**
- * Returns a new CompletionStage with the same result or exception as
- * this stage, that executes the given action using the supplied
- * Executor when this stage completes.
- *
- * <p>When this stage is complete, the given action is invoked with the
- * result (or {@code null} if none) and the exception (or {@code null}
- * if none) of this stage as arguments. The returned stage is completed
- * when the action returns.
- *
- * <p>Unlike method {@link #handleAsync(BiFunction,Executor) handleAsync},
- * this method is not designed to translate completion outcomes,
- * so the supplied action should not throw an exception. However,
- * if it does, the following rules apply: If this stage completed
- * normally but the supplied action throws an exception, then the
- * returned stage completes exceptionally with the supplied
- * action's exception. Or, if this stage completed exceptionally
- * and the supplied action throws an exception, then the returned
- * stage completes exceptionally with this stage's exception.
- *
- * @param action the action to perform
- * @param executor the executor to use for asynchronous execution
- * @return the new CompletionStage
- */
- public CompletionStage<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action,
- Executor executor);
-
- /**
- * Returns a new CompletionStage that, when this stage completes
- * exceptionally, is executed with this stage's exception as the
- * argument to the supplied function. Otherwise, if this stage
- * completes normally, then the returned stage also completes
- * normally with the same value.
- *
- * @param fn the function to use to compute the value of the
- * returned CompletionStage if this CompletionStage completed
- * exceptionally
- * @return the new CompletionStage
- */
- public CompletionStage<T> exceptionally
- (Function<Throwable, ? extends T> fn);
-
- /**
- * Returns a {@link CompletableFuture} maintaining the same
- * completion properties as this stage. If this stage is already a
- * 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}. 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/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index b4fa8aa..3ed54cf 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -13,6 +13,7 @@
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
+import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
@@ -20,29 +21,14 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
-import java.util.Spliterator;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.DoubleBinaryOperator;
-import java.util.function.Function;
-import java.util.function.IntBinaryOperator;
-import java.util.function.LongBinaryOperator;
-import java.util.function.Predicate;
-import java.util.function.ToDoubleBiFunction;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToIntBiFunction;
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongBiFunction;
-import java.util.function.ToLongFunction;
-// TODO(streams):
-//import java.util.stream.Stream;
// BEGIN android-note
// removed link to collections framework docs
+// removed links to hidden api
// END android-note
/**
@@ -66,14 +52,14 @@
* that key reporting the updated value.) For aggregate operations
* such as {@code putAll} and {@code clear}, concurrent retrievals may
* reflect insertion or removal of only some entries. Similarly,
- * Iterators, Spliterators and Enumerations return elements reflecting the
- * state of the hash table at some point at or since the creation of the
+ * Iterators and Enumerations return elements reflecting the state of
+ * the hash table at some point at or since the creation of the
* iterator/enumeration. They do <em>not</em> throw {@link
- * java.util.ConcurrentModificationException ConcurrentModificationException}.
- * However, iterators are designed to be used by only one thread at a time.
- * Bear in mind that the results of aggregate status methods including
- * {@code size}, {@code isEmpty}, and {@code containsValue} are typically
- * useful only when a map is not undergoing concurrent updates in other threads.
+ * ConcurrentModificationException}. However, iterators are designed
+ * to be used by only one thread at a time. Bear in mind that the
+ * results of aggregate status methods including {@code size}, {@code
+ * isEmpty}, and {@code containsValue} are typically useful only when
+ * a map is not undergoing concurrent updates in other threads.
* Otherwise the results of these methods reflect transient states
* that may be adequate for monitoring or estimation purposes, but not
* for program control.
@@ -100,19 +86,6 @@
* hash table. To ameliorate impact, when keys are {@link Comparable},
* this class may use comparison order among keys to help break ties.
*
- * <p>A {@link Set} projection of a ConcurrentHashMap may be created
- * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
- * (using {@link #keySet(Object)} when only keys are of interest, and the
- * mapped values are (perhaps transiently) not used or all take the
- * same mapping value.
- *
- * <p>A ConcurrentHashMap can be used as a scalable frequency map (a
- * form of histogram or multiset) by using {@link
- * java.util.concurrent.atomic.LongAdder} values and initializing via
- * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
- * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
- * {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
- *
* <p>This class and its views and iterators implement all of the
* <em>optional</em> methods of the {@link Map} and {@link Iterator}
* interfaces.
@@ -120,121 +93,15 @@
* <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
* does <em>not</em> allow {@code null} to be used as a key or value.
*
- * <p>ConcurrentHashMaps support a set of sequential and parallel bulk
- * operations that, unlike most (TODO(streams): link to Stream) methods, are designed
- * to be safely, and often sensibly, applied even with maps that are
- * being concurrently updated by other threads; for example, when
- * computing a snapshot summary of the values in a shared registry.
- * There are three kinds of operation, each with four forms, accepting
- * functions with keys, values, entries, and (key, value) pairs as
- * arguments and/or return values. Because the elements of a
- * ConcurrentHashMap are not ordered in any particular way, and may be
- * processed in different orders in different parallel executions, the
- * correctness of supplied functions should not depend on any
- * 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 java.util.Map.Entry} objects do not support method {@code
- * setValue}.
- *
- * <ul>
- * <li>forEach: Performs a given action on each element.
- * A variant form applies a given transformation on each element
- * before performing the action.
- *
- * <li>search: Returns the first available non-null result of
- * applying a given function on each element; skipping further
- * search when a result is found.
- *
- * <li>reduce: Accumulates each element. The supplied reduction
- * function cannot rely on ordering (more formally, it should be
- * both associative and commutative). There are five variants:
- *
- * <ul>
- *
- * <li>Plain reductions. (There is not a form of this method for
- * (key, value) function arguments since there is no corresponding
- * return type.)
- *
- * <li>Mapped reductions that accumulate the results of a given
- * function applied to each element.
- *
- * <li>Reductions to scalar doubles, longs, and ints, using a
- * given basis value.
- *
- * </ul>
- * </ul>
- *
- * <p>These bulk operations accept a {@code parallelismThreshold}
- * argument. Methods proceed sequentially if the current map size is
- * estimated to be less than the given threshold. Using a value of
- * {@code Long.MAX_VALUE} suppresses all parallelism. Using a value
- * of {@code 1} results in maximal parallelism by partitioning into
- * enough subtasks to fully utilize the {@link
- * ForkJoinPool#commonPool()} that is used for all parallel
- * computations. Normally, you would initially choose one of these
- * extreme values, and then measure performance of using in-between
- * values that trade off overhead versus throughput.
- *
- * <p>The concurrency properties of bulk operations follow
- * from those of ConcurrentHashMap: Any non-null result returned
- * from {@code get(key)} and related access methods bears a
- * happens-before relation with the associated insertion or
- * update. The result of any bulk operation reflects the
- * composition of these per-element relations (but is not
- * necessarily atomic with respect to the map as a whole unless it
- * is somehow known to be quiescent). Conversely, because keys
- * and values in the map are never null, null serves as a reliable
- * atomic indicator of the current lack of any result. To
- * maintain this property, null serves as an implicit basis for
- * all non-scalar reduction operations. For the double, long, and
- * int versions, the basis should be one that, when combined with
- * any other value, returns that other value (more formally, it
- * should be the identity element for the reduction). Most common
- * reductions have these properties; for example, computing a sum
- * with basis 0 or a minimum with basis MAX_VALUE.
- *
- * <p>Search and transformation functions provided as arguments
- * should similarly return null to indicate the lack of any result
- * (in which case it is not used). In the case of mapped
- * reductions, this also enables transformations to serve as
- * filters, returning null (or, in the case of primitive
- * specializations, the identity basis) if the element should not
- * be combined. You can create compound transformations and
- * filterings by composing them yourself under this "null means
- * there is nothing there now" rule before using them in search or
- * reduce operations.
- *
- * <p>Methods accepting and/or returning Entry arguments maintain
- * key-value associations. They may be useful for example when
- * finding the key for the greatest value. Note that "plain" Entry
- * arguments can be supplied using {@code new
- * AbstractMap.SimpleEntry(k,v)}.
- *
- * <p>Bulk operations may complete abruptly, throwing an
- * exception encountered in the application of a supplied
- * function. Bear in mind when handling such exceptions that other
- * concurrently executing functions could also have thrown
- * exceptions, or would have done so if the first exception had
- * not occurred.
- *
- * <p>Speedups for parallel compared to sequential forms are common
- * but not guaranteed. Parallel operations involving brief functions
- * on small maps may execute more slowly than sequential forms if the
- * underlying work to parallelize the computation is more expensive
- * than the computation itself. Similarly, parallelization may not
- * lead to much actual parallelism if all processors are busy
- * performing unrelated tasks.
- *
- * <p>All arguments to all task methods must be non-null.
- *
* @since 1.5
* @author Doug Lea
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
*/
-public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
- implements ConcurrentMap<K,V>, Serializable {
+// android-note: removed documentation about hidden newKeySet and newKeySet(int) APIs.
+// android-note: Added "extends AbstractMap<K, V>.
+public class ConcurrentHashMap<K,V> extends AbstractMap<K, V>
+ implements ConcurrentMap<K,V>, Serializable {
private static final long serialVersionUID = 7249069246763182397L;
/*
@@ -449,7 +316,7 @@
*
* Maintaining API and serialization compatibility with previous
* versions of this class introduces several oddities. Mainly: We
- * leave untouched but unused constructor arguments referring to
+ * leave untouched but unused constructor arguments refering to
* concurrencyLevel. We accept a loadFactor constructor argument,
* but apply it only to initial table capacity (which is the only
* time that we can guarantee to honor it.) We also declare an
@@ -468,6 +335,7 @@
* bulk operations.
*/
+
/* ---------------- Constants -------------- */
/**
@@ -544,7 +412,7 @@
* The number of bits used for generation stamp in sizeCtl.
* Must be at least 6 for 32bit arrays.
*/
- private static final int RESIZE_STAMP_BITS = 16;
+ private static int RESIZE_STAMP_BITS = 16;
/**
* The maximum number of threads that can help resize.
@@ -560,28 +428,19 @@
/*
* Encodings for Node hash fields. See above for explanation.
*/
- static final int MOVED = -1; // hash for forwarding nodes
- static final int TREEBIN = -2; // hash for roots of trees
- static final int RESERVED = -3; // hash for transient reservations
+ static final int MOVED = 0x8fffffff; // (-1) hash for forwarding nodes
+ static final int TREEBIN = 0x80000000; // hash for roots of trees
+ static final int RESERVED = 0x80000001; // hash for transient reservations
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
/** Number of CPUS, to place bounds on some sizings */
static final int NCPU = Runtime.getRuntime().availableProcessors();
- /**
- * Serialized pseudo-fields, provided only for jdk7 compatibility.
- * @serialField segments Segment[]
- * The segments, each of which is a specialized hash table.
- * @serialField segmentMask int
- * Mask value for indexing into segments. The upper bits of a
- * key's hash code are used to choose the segment.
- * @serialField segmentShift int
- * Shift value for indexing within segments.
- */
+ /** For serialization compatibility. */
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("segments", Segment[].class),
new ObjectStreamField("segmentMask", Integer.TYPE),
- new ObjectStreamField("segmentShift", Integer.TYPE),
+ new ObjectStreamField("segmentShift", Integer.TYPE)
};
/* ---------------- Nodes -------------- */
@@ -598,7 +457,7 @@
final int hash;
final K key;
volatile V val;
- volatile Node<K,V> next;
+ Node<K,V> next;
Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
@@ -607,12 +466,10 @@
this.next = next;
}
- public final K getKey() { return key; }
- public final V getValue() { return val; }
- public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
- public final String toString() {
- return Helpers.mapEntryToString(key, val);
- }
+ public final K getKey() { return key; }
+ public final V getValue() { return val; }
+ public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
+ public final String toString(){ return key + "=" + val; }
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
@@ -725,9 +582,8 @@
* 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 in principle require only release ordering, not
- * full volatile semantics, but are currently coded as volatile
- * writes to be conservative.
+ * and so do not need full volatile semantics, but still require
+ * ordering to maintain concurrent readability.
*/
@SuppressWarnings("unchecked")
@@ -741,7 +597,7 @@
}
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
- U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+ U.putOrderedObject(tab, ((long)i << ASHIFT) + ABASE, v);
}
/* ---------------- Fields -------------- */
@@ -1036,8 +892,6 @@
p.val = value;
}
}
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0) {
@@ -1140,8 +994,6 @@
}
}
}
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
}
}
if (validated) {
@@ -1202,15 +1054,16 @@
* operations. It does not support the {@code add} or
* {@code addAll} operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* @return the set view
*/
- public KeySetView<K,V> keySet() {
+ // android-note : changed KeySetView<K,V> to Set<K> to maintain API compatibility.
+ public Set<K> keySet() {
KeySetView<K,V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
}
@@ -1225,11 +1078,11 @@
* {@code retainAll}, and {@code clear} operations. It does not
* support the {@code add} or {@code addAll} operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}
- * and {@link Spliterator#NONNULL}.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* @return the collection view
*/
@@ -1247,11 +1100,11 @@
* {@code removeAll}, {@code retainAll}, and {@code clear}
* operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* @return the set view
*/
@@ -1349,7 +1202,7 @@
/**
* Stripped-down version of helper class used in previous version,
- * declared for the sake of serialization compatibility.
+ * declared for the sake of serialization compatibility
*/
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
@@ -1361,10 +1214,9 @@
* 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
- * the serialized fields, followed by the key (Object) and value
- * (Object) for each key-value mapping, followed by a null pair.
+ * the key (Object) and value (Object)
+ * for each key-value mapping, followed by a null pair.
* The key-value mappings are emitted in no particular order.
*/
private void writeObject(java.io.ObjectOutputStream s)
@@ -1379,8 +1231,7 @@
}
int segmentShift = 32 - sshift;
int segmentMask = ssize - 1;
- @SuppressWarnings("unchecked")
- Segment<K,V>[] segments = (Segment<K,V>[])
+ @SuppressWarnings("unchecked") Segment<K,V>[] segments = (Segment<K,V>[])
new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment<K,V>(LOAD_FACTOR);
@@ -1400,14 +1251,12 @@
}
s.writeObject(null);
s.writeObject(null);
+ segments = null; // throw away
}
/**
* 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
- * @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1423,10 +1272,8 @@
long size = 0L;
Node<K,V> p = null;
for (;;) {
- @SuppressWarnings("unchecked")
- K k = (K) s.readObject();
- @SuppressWarnings("unchecked")
- V v = (V) s.readObject();
+ @SuppressWarnings("unchecked") K k = (K) s.readObject();
+ @SuppressWarnings("unchecked") V v = (V) s.readObject();
if (k != null && v != null) {
p = new Node<K,V>(spread(k.hashCode()), k, v, p);
++size;
@@ -1445,7 +1292,7 @@
n = tableSizeFor(sz + (sz >>> 1) + 1);
}
@SuppressWarnings("unchecked")
- Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
+ Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
int mask = n - 1;
long added = 0L;
while (p != null) {
@@ -1553,544 +1400,17 @@
throw new NullPointerException();
return replaceNode(key, value, null);
}
-
- // Overrides of JDK8+ Map extension method defaults
-
- /**
- * Returns the value to which the specified key is mapped, or the
- * given default value if this map contains no mapping for the
- * key.
- *
- * @param key the key whose associated value is to be returned
- * @param defaultValue the value to return if this map contains
- * no mapping for the given key
- * @return the mapping for the key, if present; else the default value
- * @throws NullPointerException if the specified key is null
- */
- public V getOrDefault(Object key, V defaultValue) {
- V v;
- return (v = get(key)) == null ? defaultValue : v;
- }
-
- public void forEach(BiConsumer<? super K, ? super V> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V>[] t;
- if ((t = table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; ) {
- action.accept(p.key, p.val);
- }
- }
- }
-
- public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
- if (function == null) throw new NullPointerException();
- Node<K,V>[] t;
- if ((t = table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; ) {
- V oldValue = p.val;
- for (K key = p.key;;) {
- V newValue = function.apply(key, oldValue);
- if (newValue == null)
- throw new NullPointerException();
- if (replaceNode(key, newValue, oldValue) != null ||
- (oldValue = get(key)) == null)
- break;
- }
- }
- }
- }
-
- /**
- * Helper method for EntrySetView.removeIf.
- */
- boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
- if (function == null) throw new NullPointerException();
- Node<K,V>[] t;
- boolean removed = false;
- if ((t = table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; ) {
- K k = p.key;
- V v = p.val;
- Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
- if (function.test(e) && replaceNode(k, null, v) != null)
- removed = true;
- }
- }
- return removed;
- }
-
- /**
- * Helper method for ValuesView.removeIf.
- */
- boolean removeValueIf(Predicate<? super V> function) {
- if (function == null) throw new NullPointerException();
- Node<K,V>[] t;
- boolean removed = false;
- if ((t = table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; ) {
- K k = p.key;
- V v = p.val;
- if (function.test(v) && replaceNode(k, null, v) != null)
- removed = true;
- }
- }
- return removed;
- }
-
- /**
- * If the specified key is not already associated with a value,
- * attempts to compute its value using the given mapping function
- * and enters it into this map unless {@code null}. The entire
- * method invocation is performed atomically, so the function is
- * applied at most once per key. Some attempted update operations
- * on this map by other threads may be blocked while computation
- * is in progress, so the computation should be short and simple,
- * and must not attempt to update any other mappings of this map.
- *
- * @param key key with which the specified value is to be associated
- * @param mappingFunction the function to compute a value
- * @return the current (existing or computed) value associated with
- * the specified key, or null if the computed value is null
- * @throws NullPointerException if the specified key or mappingFunction
- * is null
- * @throws IllegalStateException if the computation detectably
- * attempts a recursive update to this map that would
- * otherwise never complete
- * @throws RuntimeException or Error if the mappingFunction does so,
- * in which case the mapping is left unestablished
- */
- public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
- if (key == null || mappingFunction == null)
- throw new NullPointerException();
- int h = spread(key.hashCode());
- V val = null;
- int binCount = 0;
- for (Node<K,V>[] tab = table;;) {
- 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) {
- Node<K,V> r = new ReservationNode<K,V>();
- synchronized (r) {
- if (casTabAt(tab, i, null, r)) {
- binCount = 1;
- Node<K,V> node = null;
- try {
- if ((val = mappingFunction.apply(key)) != null)
- node = new Node<K,V>(h, key, val, null);
- } finally {
- setTabAt(tab, i, node);
- }
- }
- }
- if (binCount != 0)
- break;
- }
- else if ((fh = f.hash) == MOVED)
- tab = helpTransfer(tab, f);
- else {
- boolean added = false;
- synchronized (f) {
- if (tabAt(tab, i) == f) {
- if (fh >= 0) {
- binCount = 1;
- for (Node<K,V> e = f;; ++binCount) {
- K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
- val = e.val;
- break;
- }
- Node<K,V> pred = e;
- if ((e = e.next) == null) {
- if ((val = mappingFunction.apply(key)) != null) {
- if (pred.next != null)
- throw new IllegalStateException("Recursive update");
- added = true;
- pred.next = new Node<K,V>(h, key, val, null);
- }
- break;
- }
- }
- }
- else if (f instanceof TreeBin) {
- binCount = 2;
- TreeBin<K,V> t = (TreeBin<K,V>)f;
- TreeNode<K,V> r, p;
- if ((r = t.root) != null &&
- (p = r.findTreeNode(h, key, null)) != null)
- val = p.val;
- else if ((val = mappingFunction.apply(key)) != null) {
- added = true;
- t.putTreeVal(h, key, val);
- }
- }
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
- }
- }
- if (binCount != 0) {
- if (binCount >= TREEIFY_THRESHOLD)
- treeifyBin(tab, i);
- if (!added)
- return val;
- break;
- }
- }
- }
- if (val != null)
- addCount(1L, binCount);
- return val;
- }
-
- /**
- * If the value for the specified key is present, attempts to
- * compute a new mapping given the key and its current mapped
- * value. The entire method invocation is performed atomically.
- * Some attempted update operations on this map by other threads
- * may be blocked while computation is in progress, so the
- * computation should be short and simple, and must not attempt to
- * update any other mappings of this map.
- *
- * @param key key with which a value may be associated
- * @param remappingFunction the function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key or remappingFunction
- * is null
- * @throws IllegalStateException if the computation detectably
- * attempts a recursive update to this map that would
- * otherwise never complete
- * @throws RuntimeException or Error if the remappingFunction does so,
- * in which case the mapping is unchanged
- */
- public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (key == null || remappingFunction == null)
- throw new NullPointerException();
- int h = spread(key.hashCode());
- V val = null;
- int delta = 0;
- int binCount = 0;
- for (Node<K,V>[] tab = table;;) {
- 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)
- break;
- else if ((fh = f.hash) == MOVED)
- tab = helpTransfer(tab, f);
- else {
- synchronized (f) {
- if (tabAt(tab, i) == f) {
- if (fh >= 0) {
- binCount = 1;
- for (Node<K,V> e = f, pred = null;; ++binCount) {
- K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
- val = remappingFunction.apply(key, e.val);
- if (val != null)
- e.val = val;
- else {
- delta = -1;
- Node<K,V> en = e.next;
- if (pred != null)
- pred.next = en;
- else
- setTabAt(tab, i, en);
- }
- break;
- }
- pred = e;
- if ((e = e.next) == null)
- break;
- }
- }
- else if (f instanceof TreeBin) {
- binCount = 2;
- TreeBin<K,V> t = (TreeBin<K,V>)f;
- TreeNode<K,V> r, p;
- if ((r = t.root) != null &&
- (p = r.findTreeNode(h, key, null)) != null) {
- val = remappingFunction.apply(key, p.val);
- if (val != null)
- p.val = val;
- else {
- delta = -1;
- if (t.removeTreeNode(p))
- setTabAt(tab, i, untreeify(t.first));
- }
- }
- }
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
- }
- }
- if (binCount != 0)
- break;
- }
- }
- if (delta != 0)
- addCount((long)delta, binCount);
- return val;
- }
-
- /**
- * Attempts to compute a mapping for the specified key and its
- * current mapped value (or {@code null} if there is no current
- * mapping). The entire method invocation is performed atomically.
- * Some attempted update operations on this map by other threads
- * may be blocked while computation is in progress, so the
- * computation should be short and simple, and must not attempt to
- * update any other mappings of this Map.
- *
- * @param key key with which the specified value is to be associated
- * @param remappingFunction the function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key or remappingFunction
- * is null
- * @throws IllegalStateException if the computation detectably
- * attempts a recursive update to this map that would
- * otherwise never complete
- * @throws RuntimeException or Error if the remappingFunction does so,
- * in which case the mapping is unchanged
- */
- public V compute(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (key == null || remappingFunction == null)
- throw new NullPointerException();
- int h = spread(key.hashCode());
- V val = null;
- int delta = 0;
- int binCount = 0;
- for (Node<K,V>[] tab = table;;) {
- 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) {
- Node<K,V> r = new ReservationNode<K,V>();
- synchronized (r) {
- if (casTabAt(tab, i, null, r)) {
- binCount = 1;
- Node<K,V> node = null;
- try {
- if ((val = remappingFunction.apply(key, null)) != null) {
- delta = 1;
- node = new Node<K,V>(h, key, val, null);
- }
- } finally {
- setTabAt(tab, i, node);
- }
- }
- }
- if (binCount != 0)
- break;
- }
- else if ((fh = f.hash) == MOVED)
- tab = helpTransfer(tab, f);
- else {
- synchronized (f) {
- if (tabAt(tab, i) == f) {
- if (fh >= 0) {
- binCount = 1;
- for (Node<K,V> e = f, pred = null;; ++binCount) {
- K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
- val = remappingFunction.apply(key, e.val);
- if (val != null)
- e.val = val;
- else {
- delta = -1;
- Node<K,V> en = e.next;
- if (pred != null)
- pred.next = en;
- else
- setTabAt(tab, i, en);
- }
- break;
- }
- pred = e;
- if ((e = e.next) == null) {
- val = remappingFunction.apply(key, null);
- if (val != null) {
- if (pred.next != null)
- throw new IllegalStateException("Recursive update");
- delta = 1;
- pred.next =
- new Node<K,V>(h, key, val, null);
- }
- break;
- }
- }
- }
- else if (f instanceof TreeBin) {
- binCount = 1;
- TreeBin<K,V> t = (TreeBin<K,V>)f;
- TreeNode<K,V> r, p;
- if ((r = t.root) != null)
- p = r.findTreeNode(h, key, null);
- else
- p = null;
- V pv = (p == null) ? null : p.val;
- val = remappingFunction.apply(key, pv);
- if (val != null) {
- if (p != null)
- p.val = val;
- else {
- delta = 1;
- t.putTreeVal(h, key, val);
- }
- }
- else if (p != null) {
- delta = -1;
- if (t.removeTreeNode(p))
- setTabAt(tab, i, untreeify(t.first));
- }
- }
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
- }
- }
- if (binCount != 0) {
- if (binCount >= TREEIFY_THRESHOLD)
- treeifyBin(tab, i);
- break;
- }
- }
- }
- if (delta != 0)
- addCount((long)delta, binCount);
- return val;
- }
-
- /**
- * If the specified key is not already associated with a
- * (non-null) value, associates it with the given value.
- * Otherwise, replaces the value with the results of the given
- * remapping function, or removes if {@code null}. The entire
- * method invocation is performed atomically. Some attempted
- * update operations on this map by other threads may be blocked
- * while computation is in progress, so the computation should be
- * short and simple, and must not attempt to update any other
- * mappings of this Map.
- *
- * @param key key with which the specified value is to be associated
- * @param value the value to use if absent
- * @param remappingFunction the function to recompute a value if present
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key or the
- * remappingFunction is null
- * @throws RuntimeException or Error if the remappingFunction does so,
- * in which case the mapping is unchanged
- */
- public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
- if (key == null || value == null || remappingFunction == null)
- throw new NullPointerException();
- int h = spread(key.hashCode());
- V val = null;
- int delta = 0;
- int binCount = 0;
- for (Node<K,V>[] tab = table;;) {
- 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) {
- if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
- delta = 1;
- val = value;
- break;
- }
- }
- else if ((fh = f.hash) == MOVED)
- tab = helpTransfer(tab, f);
- else {
- synchronized (f) {
- if (tabAt(tab, i) == f) {
- if (fh >= 0) {
- binCount = 1;
- for (Node<K,V> e = f, pred = null;; ++binCount) {
- K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
- val = remappingFunction.apply(e.val, value);
- if (val != null)
- e.val = val;
- else {
- delta = -1;
- Node<K,V> en = e.next;
- if (pred != null)
- pred.next = en;
- else
- setTabAt(tab, i, en);
- }
- break;
- }
- pred = e;
- if ((e = e.next) == null) {
- delta = 1;
- val = value;
- pred.next =
- new Node<K,V>(h, key, val, null);
- break;
- }
- }
- }
- else if (f instanceof TreeBin) {
- binCount = 2;
- TreeBin<K,V> t = (TreeBin<K,V>)f;
- TreeNode<K,V> r = t.root;
- TreeNode<K,V> p = (r == null) ? null :
- r.findTreeNode(h, key, null);
- val = (p == null) ? value :
- remappingFunction.apply(p.val, value);
- if (val != null) {
- if (p != null)
- p.val = val;
- else {
- delta = 1;
- t.putTreeVal(h, key, val);
- }
- }
- else if (p != null) {
- delta = -1;
- if (t.removeTreeNode(p))
- setTabAt(tab, i, untreeify(t.first));
- }
- }
- else if (f instanceof ReservationNode)
- throw new IllegalStateException("Recursive update");
- }
- }
- if (binCount != 0) {
- if (binCount >= TREEIFY_THRESHOLD)
- treeifyBin(tab, i);
- break;
- }
- }
- }
- if (delta != 0)
- addCount((long)delta, binCount);
- return val;
- }
-
// Hashtable legacy methods
/**
- * Tests if some key maps into the specified value in this table.
+ * Legacy method testing if some key maps into the specified value
+ * in this table.
*
- * <p>Note that this method is identical in functionality to
+ * This method is identical in functionality to
* {@link #containsValue(Object)}, and exists solely to ensure
* full compatibility with class {@link java.util.Hashtable},
* which supported this method prior to introduction of the
- * Java Collections Framework.
+ * Java Collections framework.
*
* @param value a value to search for
* @return {@code true} if and only if some key maps to the
@@ -2099,7 +1419,11 @@
* {@code false} otherwise
* @throws NullPointerException if the specified value is null
*/
+ // android-note : removed @deprecated tag from javadoc.
public boolean contains(Object value) {
+ // BEGIN android-note
+ // removed deprecation
+ // END android-note
return containsValue(value);
}
@@ -2138,6 +1462,8 @@
*
* @return the number of mappings
* @since 1.8
+ *
+ * @hide
*/
public long mappingCount() {
long n = sumCount();
@@ -2151,6 +1477,8 @@
* @param <K> the element type of the returned set
* @return the new set
* @since 1.8
+ *
+ * @hide
*/
public static <K> KeySetView<K,Boolean> newKeySet() {
return new KeySetView<K,Boolean>
@@ -2168,6 +1496,8 @@
* @throws IllegalArgumentException if the initial capacity of
* elements is negative
* @since 1.8
+ *
+ * @hide
*/
public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
return new KeySetView<K,Boolean>
@@ -2184,6 +1514,8 @@
* @param mappedValue the mapped value to use for any additions
* @return the set view
* @throws NullPointerException if the mappedValue is null
+ *
+ * @hide
*/
public KeySetView<K,V> keySet(V mappedValue) {
if (mappedValue == null)
@@ -2204,34 +1536,25 @@
}
Node<K,V> find(int h, Object k) {
- // loop to avoid arbitrarily deep recursion on forwarding nodes
- outer: for (Node<K,V>[] tab = nextTable;;) {
- Node<K,V> e; int n;
- if (k == null || tab == null || (n = tab.length) == 0 ||
- (e = tabAt(tab, (n - 1) & h)) == null)
- return null;
- for (;;) {
+ Node<K,V> e; int n;
+ Node<K,V>[] tab = nextTable;
+ if (k != null && tab != null && (n = tab.length) > 0 &&
+ (e = tabAt(tab, (n - 1) & h)) != null) {
+ do {
int eh; K ek;
if ((eh = e.hash) == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
- if (eh < 0) {
- if (e instanceof ForwardingNode) {
- tab = ((ForwardingNode<K,V>)e).nextTable;
- continue outer;
- }
- else
- return e.find(h, k);
- }
- if ((e = e.next) == null)
- return null;
- }
+ if (eh < 0)
+ return e.find(h, k);
+ } while ((e = e.next) != null);
}
+ return null;
}
}
/**
- * A place-holder node used in computeIfAbsent and compute.
+ * A place-holder node used in computeIfAbsent and compute
*/
static final class ReservationNode<K,V> extends Node<K,V> {
ReservationNode() {
@@ -2293,13 +1616,14 @@
CounterCell[] as; long b, s;
if ((as = counterCells) != null ||
!U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
- CounterCell a; long v; int m;
+ CounterHashCode hc; CounterCell a; long v; int m;
boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+ if ((hc = threadCounterHashCode.get()) == null ||
+ as == null || (m = as.length - 1) < 0 ||
+ (a = as[m & hc.code]) == null ||
!(uncontended =
U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
- fullAddCount(x, uncontended);
+ fullAddCount(x, hc, uncontended);
return;
}
if (check <= 1)
@@ -2380,8 +1704,17 @@
break;
else if (tab == table) {
int rs = resizeStamp(n);
- if (U.compareAndSwapInt(this, SIZECTL, sc,
- (rs << RESIZE_STAMP_SHIFT) + 2))
+ if (sc < 0) {
+ Node<K,V>[] nt;
+ if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+ sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
+ transferIndex <= 0)
+ break;
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+ transfer(tab, nt);
+ }
+ else if (U.compareAndSwapInt(this, SIZECTL, sc,
+ (rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
}
@@ -2524,112 +1857,6 @@
}
}
- /* ---------------- Counter support -------------- */
-
- /**
- * A padded cell for distributing counts. Adapted from LongAdder
- * and Striped64. See their internal docs for explanation.
- */
- //@jdk.internal.vm.annotation.Contended // android-removed
- static final class CounterCell {
- volatile long value;
- CounterCell(long x) { value = x; }
- }
-
- final long sumCount() {
- CounterCell[] as = counterCells; CounterCell a;
- long sum = baseCount;
- if (as != null) {
- for (int i = 0; i < as.length; ++i) {
- if ((a = as[i]) != null)
- sum += a.value;
- }
- }
- return sum;
- }
-
- // See LongAdder version for explanation
- private final void fullAddCount(long x, boolean wasUncontended) {
- int h;
- if ((h = ThreadLocalRandom.getProbe()) == 0) {
- ThreadLocalRandom.localInit(); // force initialization
- h = ThreadLocalRandom.getProbe();
- wasUncontended = true;
- }
- boolean collide = false; // True if last slot nonempty
- for (;;) {
- 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.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
- boolean created = false;
- try { // Recheck under lock
- CounterCell[] rs; int m, j;
- if ((rs = counterCells) != null &&
- (m = rs.length) > 0 &&
- rs[j = (m - 1) & h] == null) {
- rs[j] = r;
- created = true;
- }
- } finally {
- cellsBusy = 0;
- }
- if (created)
- break;
- continue; // Slot is now non-empty
- }
- }
- collide = false;
- }
- else if (!wasUncontended) // CAS already known to fail
- wasUncontended = true; // Continue after rehash
- else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
- break;
- else if (counterCells != as || n >= NCPU)
- collide = false; // At max size or stale
- else if (!collide)
- collide = true;
- else if (cellsBusy == 0 &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
- try {
- 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;
- }
- collide = false;
- continue; // Retry with expanded table
- }
- h = ThreadLocalRandom.advanceProbe(h);
- }
- else if (cellsBusy == 0 && counterCells == as &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
- boolean init = false;
- try { // Initialize table
- if (counterCells == as) {
- CounterCell[] rs = new CounterCell[2];
- rs[h & 1] = new CounterCell(x);
- counterCells = rs;
- init = true;
- }
- } finally {
- cellsBusy = 0;
- }
- if (init)
- break;
- }
- else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
- break; // Fall back on using base
- }
- }
-
/* ---------------- Conversion from/to TreeBins -------------- */
/**
@@ -2637,7 +1864,7 @@
* too small, in which case resizes instead.
*/
private final void treeifyBin(Node<K,V>[] tab, int index) {
- Node<K,V> b; int n;
+ Node<K,V> b; int n, sc;
if (tab != null) {
if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
tryPresize(n << 1);
@@ -2681,7 +1908,7 @@
/* ---------------- TreeNodes -------------- */
/**
- * Nodes for use in TreeBins.
+ * Nodes for use in TreeBins
*/
static final class TreeNode<K,V> extends Node<K,V> {
TreeNode<K,V> parent; // red-black tree links
@@ -2734,6 +1961,7 @@
}
}
+
/* ---------------- TreeBins -------------- */
/**
@@ -2800,7 +2028,7 @@
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
- TreeNode<K,V> xp = p;
+ TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
@@ -2878,9 +2106,13 @@
p = ((r = root) == null ? null :
r.findTreeNode(h, k, null));
} finally {
+
Thread w;
- if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
- (READER|WAITER) && (w = waiter) != null)
+ int ls;
+ do {} while (!U.compareAndSwapInt
+ (this, LOCKSTATE,
+ ls = lockState, ls - READER));
+ if (ls == (READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
return p;
@@ -2894,6 +2126,10 @@
* Finds or adds a node.
* @return null if added
*/
+ /**
+ * Finds or adds a node.
+ * @return null if added
+ */
final TreeNode<K,V> putTreeVal(int h, K k, V v) {
Class<?> kc = null;
boolean searched = false;
@@ -3244,7 +2480,7 @@
}
/**
- * Checks invariants recursively for the tree of Nodes rooted at t.
+ * Recursive invariant check
*/
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
@@ -3268,13 +2504,15 @@
return true;
}
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
private static final long LOCKSTATE;
static {
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = TreeBin.class;
LOCKSTATE = U.objectFieldOffset
- (TreeBin.class.getDeclaredField("lockState"));
- } catch (ReflectiveOperationException e) {
+ (k.getDeclaredField("lockState"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -3489,7 +2727,7 @@
}
/**
- * Exported Entry for EntryIterator.
+ * Exported Entry for EntryIterator
*/
static final class MapEntry<K,V> implements Map.Entry<K,V> {
final K key; // non-null
@@ -3503,9 +2741,7 @@
public K getKey() { return key; }
public V getValue() { return val; }
public int hashCode() { return key.hashCode() ^ val.hashCode(); }
- public String toString() {
- return Helpers.mapEntryToString(key, val);
- }
+ public String toString() { return key + "=" + val; }
public boolean equals(Object o) {
Object k, v; Map.Entry<?,?> e;
@@ -3533,866 +2769,6 @@
}
}
- static final class KeySpliterator<K,V> extends Traverser<K,V>
- implements Spliterator<K> {
- long est; // size estimate
- KeySpliterator(Node<K,V>[] tab, int size, int index, int limit,
- long est) {
- super(tab, size, index, limit);
- this.est = est;
- }
-
- public KeySpliterator<K,V> trySplit() {
- int i, f, h;
- return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
- new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
- f, est >>>= 1);
- }
-
- public void forEachRemaining(Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- for (Node<K,V> p; (p = advance()) != null;)
- action.accept(p.key);
- }
-
- public boolean tryAdvance(Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V> p;
- if ((p = advance()) == null)
- return false;
- action.accept(p.key);
- return true;
- }
-
- public long estimateSize() { return est; }
-
- public int characteristics() {
- return Spliterator.DISTINCT | Spliterator.CONCURRENT |
- Spliterator.NONNULL;
- }
- }
-
- static final class ValueSpliterator<K,V> extends Traverser<K,V>
- implements Spliterator<V> {
- long est; // size estimate
- ValueSpliterator(Node<K,V>[] tab, int size, int index, int limit,
- long est) {
- super(tab, size, index, limit);
- this.est = est;
- }
-
- public ValueSpliterator<K,V> trySplit() {
- int i, f, h;
- return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
- new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
- f, est >>>= 1);
- }
-
- public void forEachRemaining(Consumer<? super V> action) {
- if (action == null) throw new NullPointerException();
- for (Node<K,V> p; (p = advance()) != null;)
- action.accept(p.val);
- }
-
- public boolean tryAdvance(Consumer<? super V> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V> p;
- if ((p = advance()) == null)
- return false;
- action.accept(p.val);
- return true;
- }
-
- public long estimateSize() { return est; }
-
- public int characteristics() {
- return Spliterator.CONCURRENT | Spliterator.NONNULL;
- }
- }
-
- static final class EntrySpliterator<K,V> extends Traverser<K,V>
- implements Spliterator<Map.Entry<K,V>> {
- final ConcurrentHashMap<K,V> map; // To export MapEntry
- long est; // size estimate
- EntrySpliterator(Node<K,V>[] tab, int size, int index, int limit,
- long est, ConcurrentHashMap<K,V> map) {
- super(tab, size, index, limit);
- this.map = map;
- this.est = est;
- }
-
- public EntrySpliterator<K,V> trySplit() {
- int i, f, h;
- return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
- new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
- f, est >>>= 1, map);
- }
-
- public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- for (Node<K,V> p; (p = advance()) != null; )
- action.accept(new MapEntry<K,V>(p.key, p.val, map));
- }
-
- public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V> p;
- if ((p = advance()) == null)
- return false;
- action.accept(new MapEntry<K,V>(p.key, p.val, map));
- return true;
- }
-
- public long estimateSize() { return est; }
-
- public int characteristics() {
- return Spliterator.DISTINCT | Spliterator.CONCURRENT |
- Spliterator.NONNULL;
- }
- }
-
- // Parallel bulk operations
-
- /**
- * Computes initial batch value for bulk tasks. The returned value
- * is approximately exp2 of the number of times (minus one) to
- * split task by two before executing leaf action. This value is
- * faster to compute and more convenient to use as a guide to
- * splitting than is the depth, since it is used while dividing by
- * two anyway.
- */
- final int batchFor(long b) {
- long n;
- if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
- return 0;
- int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
- return (b <= 0L || (n /= b) >= sp) ? sp : (int)n;
- }
-
- /**
- * Performs the given action for each (key, value).
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param action the action
- * @since 1.8
- */
- public void forEach(long parallelismThreshold,
- BiConsumer<? super K,? super V> action) {
- if (action == null) throw new NullPointerException();
- new ForEachMappingTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- action).invoke();
- }
-
- /**
- * Performs the given action for each non-null transformation
- * of each (key, value).
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case the action is not applied)
- * @param action the action
- * @param <U> the return type of the transformer
- * @since 1.8
- */
- public <U> void forEach(long parallelismThreshold,
- BiFunction<? super K, ? super V, ? extends U> transformer,
- Consumer<? super U> action) {
- if (transformer == null || action == null)
- throw new NullPointerException();
- new ForEachTransformedMappingTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- transformer, action).invoke();
- }
-
- /**
- * Returns a non-null result from applying the given search
- * function on each (key, value), or null if none. Upon
- * success, further element processing is suppressed and the
- * results of any other parallel invocations of the search
- * function are ignored.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param searchFunction a function returning a non-null
- * result on success, else null
- * @param <U> the return type of the search function
- * @return a non-null result from applying the given search
- * function on each (key, value), or null if none
- * @since 1.8
- */
- public <U> U search(long parallelismThreshold,
- BiFunction<? super K, ? super V, ? extends U> searchFunction) {
- if (searchFunction == null) throw new NullPointerException();
- return new SearchMappingsTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- searchFunction, new AtomicReference<U>()).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all (key, value) pairs using the given reducer to
- * combine values, or null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case it is not combined)
- * @param reducer a commutative associative combining function
- * @param <U> the return type of the transformer
- * @return the result of accumulating the given transformation
- * of all (key, value) pairs
- * @since 1.8
- */
- public <U> U reduce(long parallelismThreshold,
- BiFunction<? super K, ? super V, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceMappingsTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all (key, value) pairs using the given reducer to
- * combine values, and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all (key, value) pairs
- * @since 1.8
- */
- public double reduceToDouble(long parallelismThreshold,
- ToDoubleBiFunction<? super K, ? super V> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceMappingsToDoubleTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all (key, value) pairs using the given reducer to
- * combine values, and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all (key, value) pairs
- * @since 1.8
- */
- public long reduceToLong(long parallelismThreshold,
- ToLongBiFunction<? super K, ? super V> transformer,
- long basis,
- LongBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceMappingsToLongTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all (key, value) pairs using the given reducer to
- * combine values, and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all (key, value) pairs
- * @since 1.8
- */
- public int reduceToInt(long parallelismThreshold,
- ToIntBiFunction<? super K, ? super V> transformer,
- int basis,
- IntBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceMappingsToIntTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Performs the given action for each key.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param action the action
- * @since 1.8
- */
- public void forEachKey(long parallelismThreshold,
- Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- new ForEachKeyTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- action).invoke();
- }
-
- /**
- * Performs the given action for each non-null transformation
- * of each key.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case the action is not applied)
- * @param action the action
- * @param <U> the return type of the transformer
- * @since 1.8
- */
- public <U> void forEachKey(long parallelismThreshold,
- Function<? super K, ? extends U> transformer,
- Consumer<? super U> action) {
- if (transformer == null || action == null)
- throw new NullPointerException();
- new ForEachTransformedKeyTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- transformer, action).invoke();
- }
-
- /**
- * Returns a non-null result from applying the given search
- * function on each key, or null if none. Upon success,
- * further element processing is suppressed and the results of
- * any other parallel invocations of the search function are
- * ignored.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param searchFunction a function returning a non-null
- * result on success, else null
- * @param <U> the return type of the search function
- * @return a non-null result from applying the given search
- * function on each key, or null if none
- * @since 1.8
- */
- public <U> U searchKeys(long parallelismThreshold,
- Function<? super K, ? extends U> searchFunction) {
- if (searchFunction == null) throw new NullPointerException();
- return new SearchKeysTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- searchFunction, new AtomicReference<U>()).invoke();
- }
-
- /**
- * Returns the result of accumulating all keys using the given
- * reducer to combine values, or null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param reducer a commutative associative combining function
- * @return the result of accumulating all keys using the given
- * reducer to combine values, or null if none
- * @since 1.8
- */
- public K reduceKeys(long parallelismThreshold,
- BiFunction<? super K, ? super K, ? extends K> reducer) {
- if (reducer == null) throw new NullPointerException();
- return new ReduceKeysTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all keys using the given reducer to combine values, or
- * null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case it is not combined)
- * @param reducer a commutative associative combining function
- * @param <U> the return type of the transformer
- * @return the result of accumulating the given transformation
- * of all keys
- * @since 1.8
- */
- public <U> U reduceKeys(long parallelismThreshold,
- Function<? super K, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceKeysTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all keys using the given reducer to combine values, and
- * the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all keys
- * @since 1.8
- */
- public double reduceKeysToDouble(long parallelismThreshold,
- ToDoubleFunction<? super K> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceKeysToDoubleTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all keys using the given reducer to combine values, and
- * the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all keys
- * @since 1.8
- */
- public long reduceKeysToLong(long parallelismThreshold,
- ToLongFunction<? super K> transformer,
- long basis,
- LongBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceKeysToLongTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all keys using the given reducer to combine values, and
- * the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all keys
- * @since 1.8
- */
- public int reduceKeysToInt(long parallelismThreshold,
- ToIntFunction<? super K> transformer,
- int basis,
- IntBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceKeysToIntTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Performs the given action for each value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param action the action
- * @since 1.8
- */
- public void forEachValue(long parallelismThreshold,
- Consumer<? super V> action) {
- if (action == null)
- throw new NullPointerException();
- new ForEachValueTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- action).invoke();
- }
-
- /**
- * Performs the given action for each non-null transformation
- * of each value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case the action is not applied)
- * @param action the action
- * @param <U> the return type of the transformer
- * @since 1.8
- */
- public <U> void forEachValue(long parallelismThreshold,
- Function<? super V, ? extends U> transformer,
- Consumer<? super U> action) {
- if (transformer == null || action == null)
- throw new NullPointerException();
- new ForEachTransformedValueTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- transformer, action).invoke();
- }
-
- /**
- * Returns a non-null result from applying the given search
- * function on each value, or null if none. Upon success,
- * further element processing is suppressed and the results of
- * any other parallel invocations of the search function are
- * ignored.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param searchFunction a function returning a non-null
- * result on success, else null
- * @param <U> the return type of the search function
- * @return a non-null result from applying the given search
- * function on each value, or null if none
- * @since 1.8
- */
- public <U> U searchValues(long parallelismThreshold,
- Function<? super V, ? extends U> searchFunction) {
- if (searchFunction == null) throw new NullPointerException();
- return new SearchValuesTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- searchFunction, new AtomicReference<U>()).invoke();
- }
-
- /**
- * Returns the result of accumulating all values using the
- * given reducer to combine values, or null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param reducer a commutative associative combining function
- * @return the result of accumulating all values
- * @since 1.8
- */
- public V reduceValues(long parallelismThreshold,
- BiFunction<? super V, ? super V, ? extends V> reducer) {
- if (reducer == null) throw new NullPointerException();
- return new ReduceValuesTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all values using the given reducer to combine values, or
- * null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case it is not combined)
- * @param reducer a commutative associative combining function
- * @param <U> the return type of the transformer
- * @return the result of accumulating the given transformation
- * of all values
- * @since 1.8
- */
- public <U> U reduceValues(long parallelismThreshold,
- Function<? super V, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceValuesTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all values using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all values
- * @since 1.8
- */
- public double reduceValuesToDouble(long parallelismThreshold,
- ToDoubleFunction<? super V> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceValuesToDoubleTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all values using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all values
- * @since 1.8
- */
- public long reduceValuesToLong(long parallelismThreshold,
- ToLongFunction<? super V> transformer,
- long basis,
- LongBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceValuesToLongTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all values using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all values
- * @since 1.8
- */
- public int reduceValuesToInt(long parallelismThreshold,
- ToIntFunction<? super V> transformer,
- int basis,
- IntBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceValuesToIntTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Performs the given action for each entry.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param action the action
- * @since 1.8
- */
- public void forEachEntry(long parallelismThreshold,
- Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- new ForEachEntryTask<K,V>(null, batchFor(parallelismThreshold), 0, 0, table,
- action).invoke();
- }
-
- /**
- * Performs the given action for each non-null transformation
- * of each entry.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case the action is not applied)
- * @param action the action
- * @param <U> the return type of the transformer
- * @since 1.8
- */
- public <U> void forEachEntry(long parallelismThreshold,
- Function<Map.Entry<K,V>, ? extends U> transformer,
- Consumer<? super U> action) {
- if (transformer == null || action == null)
- throw new NullPointerException();
- new ForEachTransformedEntryTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- transformer, action).invoke();
- }
-
- /**
- * Returns a non-null result from applying the given search
- * function on each entry, or null if none. Upon success,
- * further element processing is suppressed and the results of
- * any other parallel invocations of the search function are
- * ignored.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param searchFunction a function returning a non-null
- * result on success, else null
- * @param <U> the return type of the search function
- * @return a non-null result from applying the given search
- * function on each entry, or null if none
- * @since 1.8
- */
- public <U> U searchEntries(long parallelismThreshold,
- Function<Map.Entry<K,V>, ? extends U> searchFunction) {
- if (searchFunction == null) throw new NullPointerException();
- return new SearchEntriesTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- searchFunction, new AtomicReference<U>()).invoke();
- }
-
- /**
- * Returns the result of accumulating all entries using the
- * given reducer to combine values, or null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param reducer a commutative associative combining function
- * @return the result of accumulating all entries
- * @since 1.8
- */
- public Map.Entry<K,V> reduceEntries(long parallelismThreshold,
- BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
- if (reducer == null) throw new NullPointerException();
- return new ReduceEntriesTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all entries using the given reducer to combine values,
- * or null if none.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element, or null if there is no transformation (in
- * which case it is not combined)
- * @param reducer a commutative associative combining function
- * @param <U> the return type of the transformer
- * @return the result of accumulating the given transformation
- * of all entries
- * @since 1.8
- */
- public <U> U reduceEntries(long parallelismThreshold,
- Function<Map.Entry<K,V>, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceEntriesTask<K,V,U>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all entries using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all entries
- * @since 1.8
- */
- public double reduceEntriesToDouble(long parallelismThreshold,
- ToDoubleFunction<Map.Entry<K,V>> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceEntriesToDoubleTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all entries using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all entries
- * @since 1.8
- */
- public long reduceEntriesToLong(long parallelismThreshold,
- ToLongFunction<Map.Entry<K,V>> transformer,
- long basis,
- LongBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceEntriesToLongTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
- /**
- * Returns the result of accumulating the given transformation
- * of all entries using the given reducer to combine values,
- * and the given basis as an identity value.
- *
- * @param parallelismThreshold the (estimated) number of elements
- * needed for this operation to be executed in parallel
- * @param transformer a function returning the transformation
- * for an element
- * @param basis the identity (initial default value) for the reduction
- * @param reducer a commutative associative combining function
- * @return the result of accumulating the given transformation
- * of all entries
- * @since 1.8
- */
- public int reduceEntriesToInt(long parallelismThreshold,
- ToIntFunction<Map.Entry<K,V>> transformer,
- int basis,
- IntBinaryOperator reducer) {
- if (transformer == null || reducer == null)
- throw new NullPointerException();
- return new MapReduceEntriesToIntTask<K,V>
- (null, batchFor(parallelismThreshold), 0, 0, table,
- null, transformer, basis, reducer).invoke();
- }
-
-
/* ----------------Views -------------- */
/**
@@ -4422,30 +2798,30 @@
// implementations below rely on concrete classes supplying these
// abstract methods
/**
- * Returns an iterator over the elements in this collection.
- *
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * @return an iterator over the elements in this collection
+ * Returns a "weakly consistent" iterator that will never
+ * throw {@link ConcurrentModificationException}, and
+ * guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not
+ * guaranteed to) reflect any modifications subsequent to
+ * construction.
*/
public abstract Iterator<E> iterator();
public abstract boolean contains(Object o);
public abstract boolean remove(Object o);
- private static final String OOME_MSG = "Required array size too large";
+ private static final String oomeMsg = "Required array size too large";
public final Object[] toArray() {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(OOME_MSG);
+ throw new OutOfMemoryError(oomeMsg);
int n = (int)sz;
Object[] r = new Object[n];
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(OOME_MSG);
+ throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
@@ -4461,7 +2837,7 @@
public final <T> T[] toArray(T[] a) {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(OOME_MSG);
+ throw new OutOfMemoryError(oomeMsg);
int m = (int)sz;
T[] r = (a.length >= m) ? a :
(T[])java.lang.reflect.Array
@@ -4471,7 +2847,7 @@
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(OOME_MSG);
+ throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
@@ -4525,7 +2901,6 @@
}
public final boolean removeAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext();) {
if (c.contains(it.next())) {
@@ -4537,7 +2912,6 @@
}
public final boolean retainAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext();) {
if (!c.contains(it.next())) {
@@ -4556,11 +2930,12 @@
* common value. This class cannot be directly instantiated.
* See {@link #keySet() keySet()},
* {@link #keySet(Object) keySet(V)},
- * {@link #newKeySet() newKeySet()},
- * {@link #newKeySet(int) newKeySet(int)}.
*
* @since 1.8
+ *
+ * @hide
*/
+ // android-note: removed references to hidden APIs.
public static class KeySetView<K,V> extends CollectionView<K,V,K>
implements Set<K>, java.io.Serializable {
private static final long serialVersionUID = 7249069246763182397L;
@@ -4660,23 +3035,6 @@
(containsAll(c) && c.containsAll(this))));
}
- public Spliterator<K> spliterator() {
- Node<K,V>[] t;
- ConcurrentHashMap<K,V> m = map;
- long n = m.sumCount();
- int f = (t = m.table) == null ? 0 : t.length;
- return new KeySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
- }
-
- public void forEach(Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V>[] t;
- if ((t = map.table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; )
- action.accept(p.key);
- }
- }
}
/**
@@ -4718,27 +3076,6 @@
throw new UnsupportedOperationException();
}
- public boolean removeIf(Predicate<? super V> filter) {
- return map.removeValueIf(filter);
- }
-
- public Spliterator<V> spliterator() {
- Node<K,V>[] t;
- ConcurrentHashMap<K,V> m = map;
- long n = m.sumCount();
- int f = (t = m.table) == null ? 0 : t.length;
- return new ValueSpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
- }
-
- public void forEach(Consumer<? super V> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V>[] t;
- if ((t = map.table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; )
- action.accept(p.val);
- }
- }
}
/**
@@ -4791,10 +3128,6 @@
return added;
}
- public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
- return map.removeEntryIf(filter);
- }
-
public final int hashCode() {
int h = 0;
Node<K,V>[] t;
@@ -4814,1532 +3147,181 @@
(containsAll(c) && c.containsAll(this))));
}
- public Spliterator<Map.Entry<K,V>> spliterator() {
- Node<K,V>[] t;
- ConcurrentHashMap<K,V> m = map;
- long n = m.sumCount();
- int f = (t = m.table) == null ? 0 : t.length;
- return new EntrySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n, m);
- }
-
- public void forEach(Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- Node<K,V>[] t;
- if ((t = map.table) != null) {
- Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
- for (Node<K,V> p; (p = it.advance()) != null; )
- action.accept(new MapEntry<K,V>(p.key, p.val, map));
- }
- }
-
}
- // -------------------------------------------------------
+
+ /* ---------------- Counters -------------- */
+
+ // Adapted from LongAdder and Striped64.
+ // See their internal docs for explanation.
+
+ // A padded cell for distributing counts
+ static final class CounterCell {
+ volatile long p0, p1, p2, p3, p4, p5, p6;
+ volatile long value;
+ volatile long q0, q1, q2, q3, q4, q5, q6;
+ CounterCell(long x) { value = x; }
+ }
/**
- * Base class for bulk tasks. Repeats some fields and code from
- * class Traverser, because we need to subclass CountedCompleter.
+ * Holder for the thread-local hash code determining which
+ * CounterCell to use. The code is initialized via the
+ * counterHashCodeGenerator, but may be moved upon collisions.
*/
- @SuppressWarnings("serial")
- abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
- Node<K,V>[] tab; // same as Traverser
- Node<K,V> next;
- TableStack<K,V> stack, spare;
- int index;
- int baseIndex;
- int baseLimit;
- final int baseSize;
- int batch; // split control
-
- BulkTask(BulkTask<K,V,?> par, int b, int i, int f, Node<K,V>[] t) {
- super(par);
- this.batch = b;
- this.index = this.baseIndex = i;
- if ((this.tab = t) == null)
- this.baseSize = this.baseLimit = 0;
- else if (par == null)
- this.baseSize = this.baseLimit = t.length;
- else {
- this.baseLimit = f;
- this.baseSize = par.baseSize;
- }
- }
-
- /**
- * Same as Traverser version.
- */
- final Node<K,V> advance() {
- Node<K,V> e;
- if ((e = next) != null)
- e = e.next;
- for (;;) {
- Node<K,V>[] t; int i, n;
- if (e != null)
- return next = e;
- if (baseIndex >= baseLimit || (t = tab) == null ||
- (n = t.length) <= (i = index) || i < 0)
- return next = null;
- if ((e = tabAt(t, i)) != null && e.hash < 0) {
- if (e instanceof ForwardingNode) {
- tab = ((ForwardingNode<K,V>)e).nextTable;
- e = null;
- pushState(t, i, n);
- continue;
- }
- else if (e instanceof TreeBin)
- e = ((TreeBin<K,V>)e).first;
- else
- e = null;
- }
- if (stack != null)
- recoverState(n);
- else if ((index = i + baseSize) >= n)
- index = ++baseIndex;
- }
- }
-
- private void pushState(Node<K,V>[] t, int i, int n) {
- TableStack<K,V> s = spare;
- if (s != null)
- spare = s.next;
- else
- s = new TableStack<K,V>();
- s.tab = t;
- s.length = n;
- s.index = i;
- s.next = stack;
- stack = s;
- }
-
- private void recoverState(int n) {
- TableStack<K,V> s; int len;
- while ((s = stack) != null && (index += (len = s.length)) >= n) {
- n = len;
- index = s.index;
- tab = s.tab;
- s.tab = null;
- TableStack<K,V> next = s.next;
- s.next = spare; // save for reuse
- stack = next;
- spare = s;
- }
- if (s == null && (index += baseSize) >= n)
- index = ++baseIndex;
- }
+ static final class CounterHashCode {
+ int code;
}
- /*
- * Task classes. Coded in a regular but ugly format/style to
- * simplify checks that each variant differs in the right way from
- * others. The null screenings exist because compilers cannot tell
- * that we've already null-checked task arguments, so we force
- * simplest hoisted bypass to help avoid convoluted traps.
+ /**
+ * Generates initial value for per-thread CounterHashCodes.
*/
- @SuppressWarnings("serial")
- static final class ForEachKeyTask<K,V>
- extends BulkTask<K,V,Void> {
- final Consumer<? super K> action;
- ForEachKeyTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Consumer<? super K> action) {
- super(p, b, i, f, t);
- this.action = action;
- }
- public final void compute() {
- final Consumer<? super K> action;
- if ((action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachKeyTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null;)
- action.accept(p.key);
- propagateCompletion();
+ static final AtomicInteger counterHashCodeGenerator = new AtomicInteger();
+
+ /**
+ * Increment for counterHashCodeGenerator. See class ThreadLocal
+ * for explanation.
+ */
+ static final int SEED_INCREMENT = 0x61c88647;
+
+ /**
+ * Per-thread counter hash codes. Shared across all instances.
+ */
+ static final ThreadLocal<CounterHashCode> threadCounterHashCode =
+ new ThreadLocal<CounterHashCode>();
+
+ final long sumCount() {
+ CounterCell[] as = counterCells; CounterCell a;
+ long sum = baseCount;
+ if (as != null) {
+ for (int i = 0; i < as.length; ++i) {
+ if ((a = as[i]) != null)
+ sum += a.value;
}
}
+ return sum;
}
- @SuppressWarnings("serial")
- static final class ForEachValueTask<K,V>
- extends BulkTask<K,V,Void> {
- final Consumer<? super V> action;
- ForEachValueTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Consumer<? super V> action) {
- super(p, b, i, f, t);
- this.action = action;
+ // See LongAdder version for explanation
+ private final void fullAddCount(long x, CounterHashCode hc,
+ boolean wasUncontended) {
+ int h;
+ if (hc == null) {
+ hc = new CounterHashCode();
+ int s = counterHashCodeGenerator.addAndGet(SEED_INCREMENT);
+ h = hc.code = (s == 0) ? 1 : s; // Avoid zero
+ threadCounterHashCode.set(hc);
}
- public final void compute() {
- final Consumer<? super V> action;
- if ((action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachValueTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null;)
- action.accept(p.val);
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachEntryTask<K,V>
- extends BulkTask<K,V,Void> {
- final Consumer<? super Entry<K,V>> action;
- ForEachEntryTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Consumer<? super Entry<K,V>> action) {
- super(p, b, i, f, t);
- this.action = action;
- }
- public final void compute() {
- final Consumer<? super Entry<K,V>> action;
- if ((action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachEntryTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- action.accept(p);
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachMappingTask<K,V>
- extends BulkTask<K,V,Void> {
- final BiConsumer<? super K, ? super V> action;
- ForEachMappingTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- BiConsumer<? super K,? super V> action) {
- super(p, b, i, f, t);
- this.action = action;
- }
- public final void compute() {
- final BiConsumer<? super K, ? super V> action;
- if ((action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachMappingTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- action.accept(p.key, p.val);
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachTransformedKeyTask<K,V,U>
- extends BulkTask<K,V,Void> {
- final Function<? super K, ? extends U> transformer;
- final Consumer<? super U> action;
- ForEachTransformedKeyTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
- super(p, b, i, f, t);
- this.transformer = transformer; this.action = action;
- }
- public final void compute() {
- final Function<? super K, ? extends U> transformer;
- final Consumer<? super U> action;
- if ((transformer = this.transformer) != null &&
- (action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachTransformedKeyTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- transformer, action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.key)) != null)
- action.accept(u);
- }
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachTransformedValueTask<K,V,U>
- extends BulkTask<K,V,Void> {
- final Function<? super V, ? extends U> transformer;
- final Consumer<? super U> action;
- ForEachTransformedValueTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
- super(p, b, i, f, t);
- this.transformer = transformer; this.action = action;
- }
- public final void compute() {
- final Function<? super V, ? extends U> transformer;
- final Consumer<? super U> action;
- if ((transformer = this.transformer) != null &&
- (action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachTransformedValueTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- transformer, action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.val)) != null)
- action.accept(u);
- }
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachTransformedEntryTask<K,V,U>
- extends BulkTask<K,V,Void> {
- final Function<Map.Entry<K,V>, ? extends U> transformer;
- final Consumer<? super U> action;
- ForEachTransformedEntryTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<Map.Entry<K,V>, ? extends U> transformer, Consumer<? super U> action) {
- super(p, b, i, f, t);
- this.transformer = transformer; this.action = action;
- }
- public final void compute() {
- final Function<Map.Entry<K,V>, ? extends U> transformer;
- final Consumer<? super U> action;
- if ((transformer = this.transformer) != null &&
- (action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachTransformedEntryTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- transformer, action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p)) != null)
- action.accept(u);
- }
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ForEachTransformedMappingTask<K,V,U>
- extends BulkTask<K,V,Void> {
- final BiFunction<? super K, ? super V, ? extends U> transformer;
- final Consumer<? super U> action;
- ForEachTransformedMappingTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- BiFunction<? super K, ? super V, ? extends U> transformer,
- Consumer<? super U> action) {
- super(p, b, i, f, t);
- this.transformer = transformer; this.action = action;
- }
- public final void compute() {
- final BiFunction<? super K, ? super V, ? extends U> transformer;
- final Consumer<? super U> action;
- if ((transformer = this.transformer) != null &&
- (action = this.action) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- new ForEachTransformedMappingTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- transformer, action).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.key, p.val)) != null)
- action.accept(u);
- }
- propagateCompletion();
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class SearchKeysTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<? super K, ? extends U> searchFunction;
- final AtomicReference<U> result;
- SearchKeysTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<? super K, ? extends U> searchFunction,
- AtomicReference<U> result) {
- super(p, b, i, f, t);
- this.searchFunction = searchFunction; this.result = result;
- }
- public final U getRawResult() { return result.get(); }
- public final void compute() {
- final Function<? super K, ? extends U> searchFunction;
- final AtomicReference<U> result;
- if ((searchFunction = this.searchFunction) != null &&
- (result = this.result) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- if (result.get() != null)
- return;
- addToPendingCount(1);
- new SearchKeysTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- searchFunction, result).fork();
- }
- while (result.get() == null) {
- U u;
- Node<K,V> p;
- if ((p = advance()) == null) {
- propagateCompletion();
- break;
+ else
+ h = hc.code;
+ boolean collide = false; // True if last slot nonempty
+ for (;;) {
+ 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.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ boolean created = false;
+ try { // Recheck under lock
+ CounterCell[] rs; int m, j;
+ if ((rs = counterCells) != null &&
+ (m = rs.length) > 0 &&
+ rs[j = (m - 1) & h] == null) {
+ rs[j] = r;
+ created = true;
+ }
+ } finally {
+ cellsBusy = 0;
+ }
+ if (created)
+ break;
+ continue; // Slot is now non-empty
+ }
}
- if ((u = searchFunction.apply(p.key)) != null) {
- if (result.compareAndSet(null, u))
- quietlyCompleteRoot();
- break;
- }
+ collide = false;
}
+ else if (!wasUncontended) // CAS already known to fail
+ wasUncontended = true; // Continue after rehash
+ else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+ break;
+ else if (counterCells != as || n >= NCPU)
+ collide = false; // At max size or stale
+ else if (!collide)
+ collide = true;
+ else if (cellsBusy == 0 &&
+ U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ try {
+ 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;
+ }
+ collide = false;
+ continue; // Retry with expanded table
+ }
+ h ^= h << 13; // Rehash
+ h ^= h >>> 17;
+ h ^= h << 5;
}
- }
- }
-
- @SuppressWarnings("serial")
- static final class SearchValuesTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<? super V, ? extends U> searchFunction;
- final AtomicReference<U> result;
- SearchValuesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<? super V, ? extends U> searchFunction,
- AtomicReference<U> result) {
- super(p, b, i, f, t);
- this.searchFunction = searchFunction; this.result = result;
- }
- public final U getRawResult() { return result.get(); }
- public final void compute() {
- final Function<? super V, ? extends U> searchFunction;
- final AtomicReference<U> result;
- if ((searchFunction = this.searchFunction) != null &&
- (result = this.result) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- if (result.get() != null)
- return;
- addToPendingCount(1);
- new SearchValuesTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- searchFunction, result).fork();
- }
- while (result.get() == null) {
- U u;
- Node<K,V> p;
- if ((p = advance()) == null) {
- propagateCompletion();
- break;
+ else if (cellsBusy == 0 && counterCells == as &&
+ U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ boolean init = false;
+ try { // Initialize table
+ if (counterCells == as) {
+ CounterCell[] rs = new CounterCell[2];
+ rs[h & 1] = new CounterCell(x);
+ counterCells = rs;
+ init = true;
}
- if ((u = searchFunction.apply(p.val)) != null) {
- if (result.compareAndSet(null, u))
- quietlyCompleteRoot();
- break;
- }
+ } finally {
+ cellsBusy = 0;
}
+ if (init)
+ break;
}
+ else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+ break; // Fall back on using base
}
- }
-
- @SuppressWarnings("serial")
- static final class SearchEntriesTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<Entry<K,V>, ? extends U> searchFunction;
- final AtomicReference<U> result;
- SearchEntriesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- Function<Entry<K,V>, ? extends U> searchFunction,
- AtomicReference<U> result) {
- super(p, b, i, f, t);
- this.searchFunction = searchFunction; this.result = result;
- }
- public final U getRawResult() { return result.get(); }
- public final void compute() {
- final Function<Entry<K,V>, ? extends U> searchFunction;
- final AtomicReference<U> result;
- if ((searchFunction = this.searchFunction) != null &&
- (result = this.result) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- if (result.get() != null)
- return;
- addToPendingCount(1);
- new SearchEntriesTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- searchFunction, result).fork();
- }
- while (result.get() == null) {
- U u;
- Node<K,V> p;
- if ((p = advance()) == null) {
- propagateCompletion();
- break;
- }
- if ((u = searchFunction.apply(p)) != null) {
- if (result.compareAndSet(null, u))
- quietlyCompleteRoot();
- return;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class SearchMappingsTask<K,V,U>
- extends BulkTask<K,V,U> {
- final BiFunction<? super K, ? super V, ? extends U> searchFunction;
- final AtomicReference<U> result;
- SearchMappingsTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- BiFunction<? super K, ? super V, ? extends U> searchFunction,
- AtomicReference<U> result) {
- super(p, b, i, f, t);
- this.searchFunction = searchFunction; this.result = result;
- }
- public final U getRawResult() { return result.get(); }
- public final void compute() {
- final BiFunction<? super K, ? super V, ? extends U> searchFunction;
- final AtomicReference<U> result;
- if ((searchFunction = this.searchFunction) != null &&
- (result = this.result) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- if (result.get() != null)
- return;
- addToPendingCount(1);
- new SearchMappingsTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- searchFunction, result).fork();
- }
- while (result.get() == null) {
- U u;
- Node<K,V> p;
- if ((p = advance()) == null) {
- propagateCompletion();
- break;
- }
- if ((u = searchFunction.apply(p.key, p.val)) != null) {
- if (result.compareAndSet(null, u))
- quietlyCompleteRoot();
- break;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ReduceKeysTask<K,V>
- extends BulkTask<K,V,K> {
- final BiFunction<? super K, ? super K, ? extends K> reducer;
- K result;
- ReduceKeysTask<K,V> rights, nextRight;
- ReduceKeysTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- ReduceKeysTask<K,V> nextRight,
- BiFunction<? super K, ? super K, ? extends K> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.reducer = reducer;
- }
- public final K getRawResult() { return result; }
- public final void compute() {
- final BiFunction<? super K, ? super K, ? extends K> reducer;
- if ((reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new ReduceKeysTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, reducer)).fork();
- }
- K r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- K u = p.key;
- r = (r == null) ? u : u == null ? r : reducer.apply(r, u);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- ReduceKeysTask<K,V>
- t = (ReduceKeysTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- K tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ReduceValuesTask<K,V>
- extends BulkTask<K,V,V> {
- final BiFunction<? super V, ? super V, ? extends V> reducer;
- V result;
- ReduceValuesTask<K,V> rights, nextRight;
- ReduceValuesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- ReduceValuesTask<K,V> nextRight,
- BiFunction<? super V, ? super V, ? extends V> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.reducer = reducer;
- }
- public final V getRawResult() { return result; }
- public final void compute() {
- final BiFunction<? super V, ? super V, ? extends V> reducer;
- if ((reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new ReduceValuesTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, reducer)).fork();
- }
- V r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- V v = p.val;
- r = (r == null) ? v : reducer.apply(r, v);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- ReduceValuesTask<K,V>
- t = (ReduceValuesTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- V tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class ReduceEntriesTask<K,V>
- extends BulkTask<K,V,Map.Entry<K,V>> {
- final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
- Map.Entry<K,V> result;
- ReduceEntriesTask<K,V> rights, nextRight;
- ReduceEntriesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- ReduceEntriesTask<K,V> nextRight,
- BiFunction<Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.reducer = reducer;
- }
- public final Map.Entry<K,V> getRawResult() { return result; }
- public final void compute() {
- final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
- if ((reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new ReduceEntriesTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, reducer)).fork();
- }
- Map.Entry<K,V> r = null;
- for (Node<K,V> p; (p = advance()) != null; )
- r = (r == null) ? p : reducer.apply(r, p);
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- ReduceEntriesTask<K,V>
- t = (ReduceEntriesTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- Map.Entry<K,V> tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceKeysTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<? super K, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- U result;
- MapReduceKeysTask<K,V,U> rights, nextRight;
- MapReduceKeysTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceKeysTask<K,V,U> nextRight,
- Function<? super K, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.reducer = reducer;
- }
- public final U getRawResult() { return result; }
- public final void compute() {
- final Function<? super K, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceKeysTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, reducer)).fork();
- }
- U r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.key)) != null)
- r = (r == null) ? u : reducer.apply(r, u);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceKeysTask<K,V,U>
- t = (MapReduceKeysTask<K,V,U>)c,
- s = t.rights;
- while (s != null) {
- U tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceValuesTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<? super V, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- U result;
- MapReduceValuesTask<K,V,U> rights, nextRight;
- MapReduceValuesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceValuesTask<K,V,U> nextRight,
- Function<? super V, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.reducer = reducer;
- }
- public final U getRawResult() { return result; }
- public final void compute() {
- final Function<? super V, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceValuesTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, reducer)).fork();
- }
- U r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.val)) != null)
- r = (r == null) ? u : reducer.apply(r, u);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceValuesTask<K,V,U>
- t = (MapReduceValuesTask<K,V,U>)c,
- s = t.rights;
- while (s != null) {
- U tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceEntriesTask<K,V,U>
- extends BulkTask<K,V,U> {
- final Function<Map.Entry<K,V>, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- U result;
- MapReduceEntriesTask<K,V,U> rights, nextRight;
- MapReduceEntriesTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceEntriesTask<K,V,U> nextRight,
- Function<Map.Entry<K,V>, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.reducer = reducer;
- }
- public final U getRawResult() { return result; }
- public final void compute() {
- final Function<Map.Entry<K,V>, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceEntriesTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, reducer)).fork();
- }
- U r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p)) != null)
- r = (r == null) ? u : reducer.apply(r, u);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceEntriesTask<K,V,U>
- t = (MapReduceEntriesTask<K,V,U>)c,
- s = t.rights;
- while (s != null) {
- U tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceMappingsTask<K,V,U>
- extends BulkTask<K,V,U> {
- final BiFunction<? super K, ? super V, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- U result;
- MapReduceMappingsTask<K,V,U> rights, nextRight;
- MapReduceMappingsTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceMappingsTask<K,V,U> nextRight,
- BiFunction<? super K, ? super V, ? extends U> transformer,
- BiFunction<? super U, ? super U, ? extends U> reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.reducer = reducer;
- }
- public final U getRawResult() { return result; }
- public final void compute() {
- final BiFunction<? super K, ? super V, ? extends U> transformer;
- final BiFunction<? super U, ? super U, ? extends U> reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceMappingsTask<K,V,U>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, reducer)).fork();
- }
- U r = null;
- for (Node<K,V> p; (p = advance()) != null; ) {
- U u;
- if ((u = transformer.apply(p.key, p.val)) != null)
- r = (r == null) ? u : reducer.apply(r, u);
- }
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceMappingsTask<K,V,U>
- t = (MapReduceMappingsTask<K,V,U>)c,
- s = t.rights;
- while (s != null) {
- U tr, sr;
- if ((sr = s.result) != null)
- t.result = (((tr = t.result) == null) ? sr :
- reducer.apply(tr, sr));
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceKeysToDoubleTask<K,V>
- extends BulkTask<K,V,Double> {
- final ToDoubleFunction<? super K> transformer;
- final DoubleBinaryOperator reducer;
- final double basis;
- double result;
- MapReduceKeysToDoubleTask<K,V> rights, nextRight;
- MapReduceKeysToDoubleTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceKeysToDoubleTask<K,V> nextRight,
- ToDoubleFunction<? super K> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Double getRawResult() { return result; }
- public final void compute() {
- final ToDoubleFunction<? super K> transformer;
- final DoubleBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- double r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceKeysToDoubleTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceKeysToDoubleTask<K,V>
- t = (MapReduceKeysToDoubleTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsDouble(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceValuesToDoubleTask<K,V>
- extends BulkTask<K,V,Double> {
- final ToDoubleFunction<? super V> transformer;
- final DoubleBinaryOperator reducer;
- final double basis;
- double result;
- MapReduceValuesToDoubleTask<K,V> rights, nextRight;
- MapReduceValuesToDoubleTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceValuesToDoubleTask<K,V> nextRight,
- ToDoubleFunction<? super V> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Double getRawResult() { return result; }
- public final void compute() {
- final ToDoubleFunction<? super V> transformer;
- final DoubleBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- double r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceValuesToDoubleTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceValuesToDoubleTask<K,V>
- t = (MapReduceValuesToDoubleTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsDouble(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceEntriesToDoubleTask<K,V>
- extends BulkTask<K,V,Double> {
- final ToDoubleFunction<Map.Entry<K,V>> transformer;
- final DoubleBinaryOperator reducer;
- final double basis;
- double result;
- MapReduceEntriesToDoubleTask<K,V> rights, nextRight;
- MapReduceEntriesToDoubleTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceEntriesToDoubleTask<K,V> nextRight,
- ToDoubleFunction<Map.Entry<K,V>> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Double getRawResult() { return result; }
- public final void compute() {
- final ToDoubleFunction<Map.Entry<K,V>> transformer;
- final DoubleBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- double r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceEntriesToDoubleTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsDouble(r, transformer.applyAsDouble(p));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceEntriesToDoubleTask<K,V>
- t = (MapReduceEntriesToDoubleTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsDouble(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceMappingsToDoubleTask<K,V>
- extends BulkTask<K,V,Double> {
- final ToDoubleBiFunction<? super K, ? super V> transformer;
- final DoubleBinaryOperator reducer;
- final double basis;
- double result;
- MapReduceMappingsToDoubleTask<K,V> rights, nextRight;
- MapReduceMappingsToDoubleTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceMappingsToDoubleTask<K,V> nextRight,
- ToDoubleBiFunction<? super K, ? super V> transformer,
- double basis,
- DoubleBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Double getRawResult() { return result; }
- public final void compute() {
- final ToDoubleBiFunction<? super K, ? super V> transformer;
- final DoubleBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- double r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceMappingsToDoubleTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key, p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceMappingsToDoubleTask<K,V>
- t = (MapReduceMappingsToDoubleTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsDouble(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceKeysToLongTask<K,V>
- extends BulkTask<K,V,Long> {
- final ToLongFunction<? super K> transformer;
- final LongBinaryOperator reducer;
- final long basis;
- long result;
- MapReduceKeysToLongTask<K,V> rights, nextRight;
- MapReduceKeysToLongTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceKeysToLongTask<K,V> nextRight,
- ToLongFunction<? super K> transformer,
- long basis,
- LongBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Long getRawResult() { return result; }
- public final void compute() {
- final ToLongFunction<? super K> transformer;
- final LongBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- long r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceKeysToLongTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsLong(r, transformer.applyAsLong(p.key));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceKeysToLongTask<K,V>
- t = (MapReduceKeysToLongTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsLong(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceValuesToLongTask<K,V>
- extends BulkTask<K,V,Long> {
- final ToLongFunction<? super V> transformer;
- final LongBinaryOperator reducer;
- final long basis;
- long result;
- MapReduceValuesToLongTask<K,V> rights, nextRight;
- MapReduceValuesToLongTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceValuesToLongTask<K,V> nextRight,
- ToLongFunction<? super V> transformer,
- long basis,
- LongBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Long getRawResult() { return result; }
- public final void compute() {
- final ToLongFunction<? super V> transformer;
- final LongBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- long r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceValuesToLongTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsLong(r, transformer.applyAsLong(p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceValuesToLongTask<K,V>
- t = (MapReduceValuesToLongTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsLong(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceEntriesToLongTask<K,V>
- extends BulkTask<K,V,Long> {
- final ToLongFunction<Map.Entry<K,V>> transformer;
- final LongBinaryOperator reducer;
- final long basis;
- long result;
- MapReduceEntriesToLongTask<K,V> rights, nextRight;
- MapReduceEntriesToLongTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceEntriesToLongTask<K,V> nextRight,
- ToLongFunction<Map.Entry<K,V>> transformer,
- long basis,
- LongBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Long getRawResult() { return result; }
- public final void compute() {
- final ToLongFunction<Map.Entry<K,V>> transformer;
- final LongBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- long r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceEntriesToLongTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsLong(r, transformer.applyAsLong(p));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceEntriesToLongTask<K,V>
- t = (MapReduceEntriesToLongTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsLong(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceMappingsToLongTask<K,V>
- extends BulkTask<K,V,Long> {
- final ToLongBiFunction<? super K, ? super V> transformer;
- final LongBinaryOperator reducer;
- final long basis;
- long result;
- MapReduceMappingsToLongTask<K,V> rights, nextRight;
- MapReduceMappingsToLongTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceMappingsToLongTask<K,V> nextRight,
- ToLongBiFunction<? super K, ? super V> transformer,
- long basis,
- LongBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Long getRawResult() { return result; }
- public final void compute() {
- final ToLongBiFunction<? super K, ? super V> transformer;
- final LongBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- long r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceMappingsToLongTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsLong(r, transformer.applyAsLong(p.key, p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceMappingsToLongTask<K,V>
- t = (MapReduceMappingsToLongTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsLong(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceKeysToIntTask<K,V>
- extends BulkTask<K,V,Integer> {
- final ToIntFunction<? super K> transformer;
- final IntBinaryOperator reducer;
- final int basis;
- int result;
- MapReduceKeysToIntTask<K,V> rights, nextRight;
- MapReduceKeysToIntTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceKeysToIntTask<K,V> nextRight,
- ToIntFunction<? super K> transformer,
- int basis,
- IntBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Integer getRawResult() { return result; }
- public final void compute() {
- final ToIntFunction<? super K> transformer;
- final IntBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- int r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceKeysToIntTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsInt(r, transformer.applyAsInt(p.key));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceKeysToIntTask<K,V>
- t = (MapReduceKeysToIntTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsInt(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceValuesToIntTask<K,V>
- extends BulkTask<K,V,Integer> {
- final ToIntFunction<? super V> transformer;
- final IntBinaryOperator reducer;
- final int basis;
- int result;
- MapReduceValuesToIntTask<K,V> rights, nextRight;
- MapReduceValuesToIntTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceValuesToIntTask<K,V> nextRight,
- ToIntFunction<? super V> transformer,
- int basis,
- IntBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Integer getRawResult() { return result; }
- public final void compute() {
- final ToIntFunction<? super V> transformer;
- final IntBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- int r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceValuesToIntTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsInt(r, transformer.applyAsInt(p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceValuesToIntTask<K,V>
- t = (MapReduceValuesToIntTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsInt(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceEntriesToIntTask<K,V>
- extends BulkTask<K,V,Integer> {
- final ToIntFunction<Map.Entry<K,V>> transformer;
- final IntBinaryOperator reducer;
- final int basis;
- int result;
- MapReduceEntriesToIntTask<K,V> rights, nextRight;
- MapReduceEntriesToIntTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceEntriesToIntTask<K,V> nextRight,
- ToIntFunction<Map.Entry<K,V>> transformer,
- int basis,
- IntBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Integer getRawResult() { return result; }
- public final void compute() {
- final ToIntFunction<Map.Entry<K,V>> transformer;
- final IntBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- int r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceEntriesToIntTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsInt(r, transformer.applyAsInt(p));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceEntriesToIntTask<K,V>
- t = (MapReduceEntriesToIntTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsInt(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
- }
-
- @SuppressWarnings("serial")
- static final class MapReduceMappingsToIntTask<K,V>
- extends BulkTask<K,V,Integer> {
- final ToIntBiFunction<? super K, ? super V> transformer;
- final IntBinaryOperator reducer;
- final int basis;
- int result;
- MapReduceMappingsToIntTask<K,V> rights, nextRight;
- MapReduceMappingsToIntTask
- (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
- MapReduceMappingsToIntTask<K,V> nextRight,
- ToIntBiFunction<? super K, ? super V> transformer,
- int basis,
- IntBinaryOperator reducer) {
- super(p, b, i, f, t); this.nextRight = nextRight;
- this.transformer = transformer;
- this.basis = basis; this.reducer = reducer;
- }
- public final Integer getRawResult() { return result; }
- public final void compute() {
- final ToIntBiFunction<? super K, ? super V> transformer;
- final IntBinaryOperator reducer;
- if ((transformer = this.transformer) != null &&
- (reducer = this.reducer) != null) {
- int r = this.basis;
- for (int i = baseIndex, f, h; batch > 0 &&
- (h = ((f = baseLimit) + i) >>> 1) > i;) {
- addToPendingCount(1);
- (rights = new MapReduceMappingsToIntTask<K,V>
- (this, batch >>>= 1, baseLimit = h, f, tab,
- rights, transformer, r, reducer)).fork();
- }
- for (Node<K,V> p; (p = advance()) != null; )
- r = reducer.applyAsInt(r, transformer.applyAsInt(p.key, p.val));
- result = r;
- CountedCompleter<?> c;
- for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked")
- MapReduceMappingsToIntTask<K,V>
- t = (MapReduceMappingsToIntTask<K,V>)c,
- s = t.rights;
- while (s != null) {
- t.result = reducer.applyAsInt(t.result, s.result);
- s = t.rights = s.nextRight;
- }
- }
- }
- }
+ hc.code = h; // Record index for next time
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
- private static final int ABASE;
+ private static final long ABASE;
private static final int ASHIFT;
static {
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ConcurrentHashMap.class;
SIZECTL = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
+ (k.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
+ (k.getDeclaredField("transferIndex"));
BASECOUNT = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("baseCount"));
+ (k.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
-
+ (k.getDeclaredField("cellsBusy"));
+ Class<?> ck = CounterCell.class;
CELLVALUE = U.objectFieldOffset
- (CounterCell.class.getDeclaredField("value"));
-
- ABASE = U.arrayBaseOffset(Node[].class);
- int scale = U.arrayIndexScale(Node[].class);
+ (ck.getDeclaredField("value"));
+ Class<?> ak = Node[].class;
+ ABASE = U.arrayBaseOffset(ak);
+ int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
+ throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (ReflectiveOperationException e) {
+ } catch (Exception e) {
throw new Error(e);
}
@@ -6347,4 +3329,5 @@
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
Class<?> ensureLoaded = LockSupport.class;
}
+
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 7084d14..b38d6a5 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -7,16 +7,12 @@
package java.util.concurrent;
import java.util.AbstractCollection;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
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.function.Consumer;
// BEGIN android-note
// removed link to collections framework docs
@@ -31,8 +27,12 @@
* Like most other concurrent collection implementations, this class
* does not permit the use of {@code null} elements.
*
- * <p>Iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the deque at some point at or since the
+ * creation of the iterator. They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations.
*
* <p>Beware that, unlike in most collections, the {@code size} method
* is <em>NOT</em> a constant-time operation. Because of the
@@ -59,7 +59,7 @@
* @since 1.7
* @author Doug Lea
* @author Martin Buchholz
- * @param <E> the type of elements held in this deque
+ * @param <E> the type of elements held in this collection
*/
public class ConcurrentLinkedDeque<E>
extends AbstractCollection<E>
@@ -272,45 +272,47 @@
* only be seen after publication via casNext or casPrev.
*/
Node(E item) {
- U.putObject(this, ITEM, item);
+ UNSAFE.putObject(this, itemOffset, item);
}
boolean casItem(E cmp, E val) {
- return U.compareAndSwapObject(this, ITEM, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
void lazySetNext(Node<E> val) {
- U.putOrderedObject(this, NEXT, val);
+ UNSAFE.putOrderedObject(this, nextOffset, val);
}
boolean casNext(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
void lazySetPrev(Node<E> val) {
- U.putOrderedObject(this, PREV, val);
+ UNSAFE.putOrderedObject(this, prevOffset, val);
}
boolean casPrev(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, PREV, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, prevOffset, 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;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long prevOffset;
+ private static final long itemOffset;
+ private static final long nextOffset;
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) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Node.class;
+ prevOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("prev"));
+ itemOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("item"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -320,7 +322,8 @@
* Links e as first element.
*/
private void linkFirst(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ checkNotNull(e);
+ final Node<E> newNode = new Node<E>(e);
restartFromHead:
for (;;)
@@ -352,7 +355,8 @@
* Links e as last element.
*/
private void linkLast(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ checkNotNull(e);
+ final Node<E> newNode = new Node<E>(e);
restartFromTail:
for (;;)
@@ -757,6 +761,16 @@
// Minor convenience utilities
/**
+ * Throws NullPointerException if argument is null.
+ *
+ * @param v the element
+ */
+ private static void checkNotNull(Object v) {
+ if (v == null)
+ throw new NullPointerException();
+ }
+
+ /**
* Returns element unless it is null, in which case throws
* NoSuchElementException.
*
@@ -770,6 +784,22 @@
}
/**
+ * Creates an array list and fills it with elements of this list.
+ * Used by toArray.
+ *
+ * @return the array list
+ */
+ private ArrayList<E> toArrayList() {
+ ArrayList<E> list = new ArrayList<E>();
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null)
+ list.add(item);
+ }
+ return list;
+ }
+
+ /**
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
@@ -789,7 +819,8 @@
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
for (E e : c) {
- Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ checkNotNull(e);
+ Node<E> newNode = new Node<E>(e);
if (h == null)
h = t = newNode;
else {
@@ -964,42 +995,23 @@
}
public E poll() { return pollFirst(); }
- public E peek() { return peekFirst(); }
-
- /**
- * @throws NoSuchElementException {@inheritDoc}
- */
public E remove() { return removeFirst(); }
-
- /**
- * @throws NoSuchElementException {@inheritDoc}
- */
+ public E peek() { return peekFirst(); }
+ public E element() { return getFirst(); }
+ public void push(E e) { addFirst(e); }
public E pop() { return removeFirst(); }
/**
- * @throws NoSuchElementException {@inheritDoc}
- */
- public E element() { return getFirst(); }
-
- /**
- * @throws NullPointerException {@inheritDoc}
- */
- public void push(E e) { addFirst(e); }
-
- /**
- * Removes the first occurrence of the specified element from this deque.
+ * Removes the first element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
* If the deque does not contain the element, it is unchanged.
- * More formally, removes the first element {@code e} such that
- * {@code o.equals(e)} (if such an element exists).
- * Returns {@code true} if this deque contained the specified element
- * (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
* @throws NullPointerException if the specified element is null
*/
public boolean removeFirstOccurrence(Object o) {
- Objects.requireNonNull(o);
+ checkNotNull(o);
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
@@ -1011,19 +1023,16 @@
}
/**
- * Removes the last occurrence of the specified element from this deque.
+ * Removes the last element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
* If the deque does not contain the element, it is unchanged.
- * More formally, removes the last element {@code e} such that
- * {@code o.equals(e)} (if such an element exists).
- * Returns {@code true} if this deque contained the specified element
- * (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
* @throws NullPointerException if the specified element is null
*/
public boolean removeLastOccurrence(Object o) {
- Objects.requireNonNull(o);
+ checkNotNull(o);
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
@@ -1035,20 +1044,18 @@
}
/**
- * Returns {@code true} if this deque contains the specified element.
- * More formally, returns {@code true} if and only if this deque contains
- * at least one element {@code e} such that {@code o.equals(e)}.
+ * Returns {@code true} if this deque contains at least one
+ * element {@code e} such that {@code o.equals(e)}.
*
* @param o element whose presence in this deque is to be tested
* @return {@code true} if this deque contains the specified element
*/
public boolean contains(Object o) {
- 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;
- }
+ if (o == null) return false;
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item))
+ return true;
}
return false;
}
@@ -1079,28 +1086,19 @@
* @return the number of elements in this deque
*/
public int size() {
- 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 restartFromHead;
- }
- return count;
- }
+ int count = 0;
+ for (Node<E> p = first(); p != null; p = succ(p))
+ if (p.item != null)
+ // Collection.size() spec says to max out
+ if (++count == Integer.MAX_VALUE)
+ break;
+ return count;
}
/**
- * Removes the first occurrence of the specified element from this deque.
+ * Removes the first element {@code e} such that
+ * {@code o.equals(e)}, if such an element exists in this deque.
* If the deque does not contain the element, it is unchanged.
- * More formally, removes the first element {@code e} such that
- * {@code o.equals(e)} (if such an element exists).
- * Returns {@code true} if this deque contained the specified element
- * (or equivalently, if this deque changed as a result of the call).
- *
- * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
@@ -1130,7 +1128,8 @@
// 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));
+ checkNotNull(e);
+ Node<E> newNode = new Node<E>(e);
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
@@ -1181,62 +1180,6 @@
;
}
- public String toString() {
- String[] a = null;
- restartFromHead: for (;;) {
- int charLength = 0;
- int size = 0;
- for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
- if (a == null)
- a = new String[4];
- else if (size == a.length)
- a = Arrays.copyOf(a, 2 * size);
- String s = item.toString();
- a[size++] = s;
- charLength += s.length();
- }
- if (p == (p = p.next))
- continue restartFromHead;
- }
-
- if (size == 0)
- return "[]";
-
- return Helpers.toString(a, size, charLength);
- }
- }
-
- private Object[] toArrayInternal(Object[] a) {
- Object[] x = a;
- restartFromHead: for (;;) {
- int size = 0;
- for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
- if (x == null)
- x = new Object[4];
- else if (size == x.length)
- x = Arrays.copyOf(x, 2 * (size + 4));
- x[size++] = item;
- }
- if (p == (p = p.next))
- continue restartFromHead;
- }
- if (x == null)
- return new Object[0];
- else if (a != null && size <= a.length) {
- if (a != x)
- System.arraycopy(x, 0, a, 0, size);
- if (size < a.length)
- a[size] = null;
- return a;
- }
- return (size == x.length) ? x : Arrays.copyOf(x, size);
- }
- }
-
/**
* Returns an array containing all of the elements in this deque, in
* proper sequence (from first to last element).
@@ -1251,7 +1194,7 @@
* @return an array containing all of the elements in this deque
*/
public Object[] toArray() {
- return toArrayInternal(null);
+ return toArrayList().toArray();
}
/**
@@ -1277,7 +1220,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -1291,18 +1234,20 @@
* this deque
* @throws NullPointerException if the specified array is null
*/
- @SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- if (a == null) throw new NullPointerException();
- return (T[]) toArrayInternal(a);
+ return toArrayList().toArray(a);
}
/**
* 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).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this deque in proper sequence
*/
@@ -1315,8 +1260,12 @@
* sequential order. The elements will be returned in order from
* last (tail) to first (head).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this deque in reverse order
*/
@@ -1361,7 +1310,7 @@
Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
for (;; p = nextNode(p)) {
if (p == null) {
- // might be at active end or TERMINATOR node; both are OK
+ // p might be active end or TERMINATOR node; both are OK
nextNode = null;
nextItem = null;
break;
@@ -1407,121 +1356,9 @@
Node<E> nextNode(Node<E> p) { return pred(p); }
}
- /** A customized variant of Spliterators.IteratorSpliterator */
- 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;
- 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));
- }
- }
- }
- return null;
- }
-
- public void forEachRemaining(Consumer<? super E> action) {
- Node<E> p;
- if (action == null) throw new NullPointerException();
- final ConcurrentLinkedDeque<E> q = this.queue;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
- exhausted = true;
- 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) {
- Node<E> p;
- 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 = q.first();
- } while (e == null && p != null);
- if ((current = p) == null)
- exhausted = true;
- if (e != null) {
- action.accept(e);
- return true;
- }
- }
- return false;
- }
-
- public long estimateSize() { return Long.MAX_VALUE; }
-
- public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
- }
- }
-
- /**
- * Returns a {@link Spliterator} over the elements in this deque.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this deque
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return new CLDSpliterator<E>(this);
- }
-
/**
* Saves this deque to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData All of the elements (each an {@code E}) in
* the proper order, followed by a null
*/
@@ -1544,10 +1381,6 @@
/**
* Reconstitutes this deque 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1555,7 +1388,8 @@
// Read in elements until trailing null sentinel found
Node<E> h = null, t = null;
- for (Object item; (item = s.readObject()) != null; ) {
+ Object item;
+ while ((item = s.readObject()) != null) {
@SuppressWarnings("unchecked")
Node<E> newNode = new Node<E>((E) item);
if (h == null)
@@ -1570,29 +1404,31 @@
}
private boolean casHead(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
}
private boolean casTail(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
+ private static final long tailOffset;
static {
PREV_TERMINATOR = new Node<Object>();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>();
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
try {
- HEAD = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ConcurrentLinkedDeque.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ tailOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("tail"));
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index e96b1b8..9010cbe 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -7,15 +7,11 @@
package java.util.concurrent;
import java.util.AbstractQueue;
-import java.util.Arrays;
+import java.util.ArrayList;
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.function.Consumer;
// BEGIN android-note
// removed link to collections framework docs
@@ -72,7 +68,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
implements Queue<E>, java.io.Serializable {
@@ -152,28 +148,45 @@
private static class Node<E> {
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 casNext.
- */
- static <E> Node<E> newNode(E item) {
- Node<E> node = new Node<E>();
- U.putObject(node, ITEM, item);
- return node;
- }
+ /**
+ * Constructs a new node. Uses relaxed write because item can
+ * only be seen after publication via casNext.
+ */
+ Node(E item) {
+ UNSAFE.putObject(this, itemOffset, item);
+ }
- static <E> boolean casItem(Node<E> node, E cmp, E val) {
- return U.compareAndSwapObject(node, ITEM, cmp, val);
- }
+ boolean casItem(E cmp, E val) {
+ return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+ }
- static <E> void lazySetNext(Node<E> node, Node<E> val) {
- U.putOrderedObject(node, NEXT, val);
- }
+ void lazySetNext(Node<E> val) {
+ UNSAFE.putOrderedObject(this, nextOffset, val);
+ }
- static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(node, NEXT, cmp, val);
+ boolean casNext(Node<E> cmp, Node<E> val) {
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ }
+
+ // Unsafe mechanics
+
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long itemOffset;
+ private static final long nextOffset;
+
+ static {
+ try {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Node.class;
+ itemOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("item"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
}
/**
@@ -188,7 +201,7 @@
* - it is permitted for tail to lag behind head, that is, for tail
* to not be reachable from head!
*/
- transient volatile Node<E> head;
+ private transient volatile Node<E> head;
/**
* A node from which the last node on list (that is, the unique
@@ -208,7 +221,7 @@
* Creates a {@code ConcurrentLinkedQueue} that is initially empty.
*/
public ConcurrentLinkedQueue() {
- head = tail = newNode(null);
+ head = tail = new Node<E>(null);
}
/**
@@ -223,16 +236,17 @@
public ConcurrentLinkedQueue(Collection<? extends E> c) {
Node<E> h = null, t = null;
for (E e : c) {
- Node<E> newNode = newNode(Objects.requireNonNull(e));
+ checkNotNull(e);
+ Node<E> newNode = new Node<E>(e);
if (h == null)
h = t = newNode;
else {
- lazySetNext(t, newNode);
+ t.lazySetNext(newNode);
t = newNode;
}
}
if (h == null)
- h = t = newNode(null);
+ h = t = new Node<E>(null);
head = h;
tail = t;
}
@@ -256,9 +270,8 @@
* as sentinel for succ(), below.
*/
final void updateHead(Node<E> h, Node<E> p) {
- // assert h != null && p != null && (h == p || h.item == null);
if (h != p && casHead(h, p))
- lazySetNext(h, h);
+ h.lazySetNext(h);
}
/**
@@ -279,13 +292,14 @@
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- final Node<E> newNode = newNode(Objects.requireNonNull(e));
+ checkNotNull(e);
+ final Node<E> newNode = new Node<E>(e);
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, newNode)) {
+ if (p.casNext(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
@@ -313,7 +327,7 @@
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
- if (item != null && casItem(p, item, null)) {
+ if (item != null && p.casItem(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
@@ -400,17 +414,13 @@
* @return the number of elements in this queue
*/
public int size() {
- 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 restartFromHead;
- }
- return count;
- }
+ int count = 0;
+ for (Node<E> p = first(); p != null; p = succ(p))
+ if (p.item != null)
+ // Collection.size() spec says to max out
+ if (++count == Integer.MAX_VALUE)
+ break;
+ return count;
}
/**
@@ -422,12 +432,11 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- 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;
- }
+ if (o == null) return false;
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item))
+ return true;
}
return false;
}
@@ -444,25 +453,19 @@
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
- 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;
- }
- removed = casItem(p, item, null);
- }
-
- next = succ(p);
- if (pred != null && next != null) // unlink
- casNext(pred, p, next);
- if (removed)
- return true;
+ if (o == null) return false;
+ Node<E> pred = null;
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null &&
+ o.equals(item) &&
+ p.casItem(item, null)) {
+ Node<E> next = succ(p);
+ if (pred != null && next != null)
+ pred.casNext(p, next);
+ return true;
}
+ pred = p;
}
return false;
}
@@ -487,11 +490,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));
+ checkNotNull(e);
+ Node<E> newNode = new Node<E>(e);
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- lazySetNext(last, newNode);
+ last.lazySetNext(newNode);
last = newNode;
}
}
@@ -503,7 +507,7 @@
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, beginningOfTheEnd)) {
+ if (p.casNext(null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this queue.
if (!casTail(t, last)) {
@@ -529,62 +533,6 @@
}
}
- public String toString() {
- String[] a = null;
- restartFromHead: for (;;) {
- int charLength = 0;
- int size = 0;
- for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
- if (a == null)
- a = new String[4];
- else if (size == a.length)
- a = Arrays.copyOf(a, 2 * size);
- String s = item.toString();
- a[size++] = s;
- charLength += s.length();
- }
- if (p == (p = p.next))
- continue restartFromHead;
- }
-
- if (size == 0)
- return "[]";
-
- return Helpers.toString(a, size, charLength);
- }
- }
-
- private Object[] toArrayInternal(Object[] a) {
- Object[] x = a;
- restartFromHead: for (;;) {
- int size = 0;
- for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
- if (x == null)
- x = new Object[4];
- else if (size == x.length)
- x = Arrays.copyOf(x, 2 * (size + 4));
- x[size++] = item;
- }
- if (p == (p = p.next))
- continue restartFromHead;
- }
- if (x == null)
- return new Object[0];
- else if (a != null && size <= a.length) {
- if (a != x)
- System.arraycopy(x, 0, a, 0, size);
- if (size < a.length)
- a[size] = null;
- return a;
- }
- return (size == x.length) ? x : Arrays.copyOf(x, size);
- }
- }
-
/**
* Returns an array containing all of the elements in this queue, in
* proper sequence.
@@ -599,7 +547,14 @@
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
- return toArrayInternal(null);
+ // Use ArrayList to deal with resizing.
+ ArrayList<E> al = new ArrayList<E>();
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null)
+ al.add(item);
+ }
+ return al.toArray();
}
/**
@@ -623,7 +578,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -639,16 +594,40 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- if (a == null) throw new NullPointerException();
- return (T[]) toArrayInternal(a);
+ // try to use sent-in array
+ int k = 0;
+ Node<E> p;
+ for (p = first(); p != null && k < a.length; p = succ(p)) {
+ E item = p.item;
+ if (item != null)
+ a[k++] = (T)item;
+ }
+ if (p == null) {
+ if (k < a.length)
+ a[k] = null;
+ return a;
+ }
+
+ // If won't fit, use ArrayList version
+ ArrayList<E> al = new ArrayList<E>();
+ for (Node<E> q = first(); q != null; q = succ(q)) {
+ E item = q.item;
+ if (item != null)
+ al.add(item);
+ }
+ return al.toArray(a);
}
/**
* 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).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this queue in proper sequence
*/
@@ -676,47 +655,54 @@
private Node<E> lastRet;
Itr() {
- restartFromHead: for (;;) {
- Node<E> h, p, q;
- for (p = h = head;; p = q) {
- E item;
- if ((item = p.item) != null) {
- nextNode = p;
- nextItem = item;
- break;
- }
- else if ((q = p.next) == null)
- break;
- else if (p == q)
- continue restartFromHead;
+ advance();
+ }
+
+ /**
+ * Moves to next valid node and returns item to return for
+ * next(), or null if no such.
+ */
+ private E advance() {
+ lastRet = nextNode;
+ E x = nextItem;
+
+ Node<E> pred, p;
+ if (nextNode == null) {
+ p = first();
+ pred = null;
+ } else {
+ pred = nextNode;
+ p = succ(nextNode);
+ }
+
+ for (;;) {
+ if (p == null) {
+ nextNode = null;
+ nextItem = null;
+ return x;
}
- updateHead(h, p);
- return;
+ E item = p.item;
+ if (item != null) {
+ nextNode = p;
+ nextItem = item;
+ return x;
+ } else {
+ // skip over nulls
+ Node<E> next = succ(p);
+ if (pred != null && next != null)
+ pred.casNext(p, next);
+ p = next;
+ }
}
}
public boolean hasNext() {
- return nextItem != null;
+ return nextNode != null;
}
public E next() {
- final Node<E> pred = nextNode;
- if (pred == null) throw new NoSuchElementException();
- // assert nextItem != null;
- lastRet = pred;
- E item = null;
-
- for (Node<E> p = succ(pred), q;; p = q) {
- if (p == null || (item = p.item) != null) {
- nextNode = p;
- E x = nextItem;
- nextItem = item;
- return x;
- }
- // unlink deleted nodes
- if ((q = succ(p)) != null)
- casNext(pred, p, q);
- }
+ if (nextNode == null) throw new NoSuchElementException();
+ return advance();
}
public void remove() {
@@ -731,8 +717,6 @@
/**
* Saves this queue to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData All of the elements (each an {@code E}) in
* the proper order, followed by a null
*/
@@ -755,10 +739,6 @@
/**
* 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -766,156 +746,55 @@
// Read in elements until trailing null sentinel found
Node<E> h = null, t = null;
- for (Object item; (item = s.readObject()) != null; ) {
+ Object item;
+ while ((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 {
- lazySetNext(t, newNode);
+ t.lazySetNext(newNode);
t = newNode;
}
}
if (h == null)
- h = t = newNode(null);
+ h = t = new Node<E>(null);
head = h;
tail = t;
}
- /** A customized variant of Spliterators.IteratorSpliterator */
- 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;
- 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));
- }
- }
- return null;
- }
-
- public void forEachRemaining(Consumer<? super E> action) {
- 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;
- 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) {
- Node<E> p;
- 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 = q.first();
- } while (e == null && p != null);
- if ((current = p) == null)
- exhausted = true;
- if (e != null) {
- action.accept(e);
- return true;
- }
- }
- return false;
- }
-
- public long estimateSize() { return Long.MAX_VALUE; }
-
- public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
- }
- }
-
/**
- * Returns a {@link Spliterator} over the elements in this queue.
+ * Throws NullPointerException if argument is null.
*
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this queue
- * @since 1.8
+ * @param v the element
*/
- @Override
- public Spliterator<E> spliterator() {
- return new CLQSpliterator<E>(this);
+ private static void checkNotNull(Object v) {
+ if (v == null)
+ throw new NullPointerException();
}
private boolean casTail(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
}
private boolean casHead(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
}
// Unsafe mechanics
- 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;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
+ private static final long tailOffset;
static {
try {
- 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) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ConcurrentLinkedQueue.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ tailOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("tail"));
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
index ae4d221..1391f04 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -7,27 +7,14 @@
package java.util.concurrent;
import java.util.Map;
-import java.util.Objects;
-import java.util.function.BiConsumer;
-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 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}
- * must be overridden by implementations of this interface. Similarly,
- * implementations of the collections returned by methods {@link
- * #keySet}, {@link #values}, and {@link #entrySet} must override
- * methods such as {@code removeIf} when necessary to
- * preserve atomicity guarantees.
+ * A {@link java.util.Map} providing additional atomic
+ * {@code putIfAbsent}, {@code remove}, and {@code replace} methods.
*
* <p>Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
@@ -42,65 +29,11 @@
* @param <V> the type of mapped values
*/
public interface ConcurrentMap<K,V> extends Map<K,V> {
-
- /**
- * {@inheritDoc}
- *
- * @implNote This implementation assumes that the ConcurrentMap cannot
- * contain null values and {@code get()} returning null unambiguously means
- * the key is absent. Implementations which support null values
- * <strong>must</strong> override this default implementation.
- *
- * @throws ClassCastException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default V getOrDefault(Object key, V defaultValue) {
- V v;
- return ((v = get(key)) != null) ? v : defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @implSpec The default implementation is equivalent to, for this
- * {@code map}:
- * <pre> {@code
- * for (Map.Entry<K,V> entry : map.entrySet()) {
- * action.accept(entry.getKey(), entry.getValue());
- * }}</pre>
- *
- * @implNote The default implementation assumes that
- * {@code IllegalStateException} thrown by {@code getKey()} or
- * {@code getValue()} indicates that the entry has been removed and cannot
- * be processed. Operation continues for subsequent entries.
- *
- * @throws NullPointerException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default void forEach(BiConsumer<? super K, ? super V> action) {
- Objects.requireNonNull(action);
- for (Map.Entry<K,V> entry : entrySet()) {
- K k;
- V v;
- try {
- k = entry.getKey();
- v = entry.getValue();
- } catch (IllegalStateException ise) {
- // this usually means the entry is no longer in the map.
- continue;
- }
- action.accept(k, v);
- }
- }
-
/**
* If the specified key is not already associated
- * with a value, associates it with the given value.
- * This is equivalent to, for this {@code map}:
- * <pre> {@code
+ * with a value, associate it with the given value.
+ * This is equivalent to
+ * <pre> {@code
* if (!map.containsKey(key))
* return map.put(key, value);
* else
@@ -108,9 +41,6 @@
*
* except that the action is performed atomically.
*
- * @implNote This implementation intentionally re-abstracts the
- * inappropriate default provided in {@code Map}.
- *
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
@@ -131,21 +61,16 @@
/**
* Removes the entry for a key only if currently mapped to a given value.
- * This is equivalent to, for this {@code map}:
- * <pre> {@code
- * if (map.containsKey(key)
- * && Objects.equals(map.get(key), value)) {
+ * This is equivalent to
+ * <pre> {@code
+ * if (map.containsKey(key) && map.get(key).equals(value)) {
* map.remove(key);
* return true;
- * } else {
- * return false;
- * }}</pre>
+ * } else
+ * return false;}</pre>
*
* except that the action is performed atomically.
*
- * @implNote This implementation intentionally re-abstracts the
- * inappropriate default provided in {@code Map}.
- *
* @param key key with which the specified value is associated
* @param value value expected to be associated with the specified key
* @return {@code true} if the value was removed
@@ -153,30 +78,25 @@
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
- * (<a href="../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="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object key, Object value);
/**
* Replaces the entry for a key only if currently mapped to a given value.
- * This is equivalent to, for this {@code map}:
- * <pre> {@code
- * if (map.containsKey(key)
- * && Objects.equals(map.get(key), oldValue)) {
+ * This is equivalent to
+ * <pre> {@code
+ * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
* map.put(key, newValue);
* return true;
- * } else {
- * return false;
- * }}</pre>
+ * } else
+ * return false;}</pre>
*
* except that the action is performed atomically.
*
- * @implNote This implementation intentionally re-abstracts the
- * inappropriate default provided in {@code Map}.
- *
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
@@ -194,18 +114,15 @@
/**
* Replaces the entry for a key only if currently mapped to some value.
- * This is equivalent to, for this {@code map}:
- * <pre> {@code
- * if (map.containsKey(key))
+ * This is equivalent to
+ * <pre> {@code
+ * if (map.containsKey(key)) {
* return map.put(key, value);
- * else
+ * } else
* return null;}</pre>
*
* except that the action is performed atomically.
*
- * @implNote This implementation intentionally re-abstracts the
- * inappropriate default provided in {@code Map}.
- *
* @param key key with which the specified value is associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
@@ -223,251 +140,4 @@
* or value prevents it from being stored in this map
*/
V replace(K key, V value);
-
- /**
- * {@inheritDoc}
- *
- * @implSpec
- * <p>The default implementation is equivalent to, for this {@code map}:
- * <pre> {@code
- * for (Map.Entry<K,V> entry : map.entrySet()) {
- * K k;
- * V v;
- * do {
- * k = entry.getKey();
- * v = entry.getValue();
- * } while (!map.replace(k, v, function.apply(k, v)));
- * }}</pre>
- *
- * The default implementation may retry these steps when multiple
- * threads attempt updates including potentially calling the function
- * repeatedly for a given key.
- *
- * <p>This implementation assumes that the ConcurrentMap cannot contain null
- * values and {@code get()} returning null unambiguously means the key is
- * absent. Implementations which support null values <strong>must</strong>
- * override this default implementation.
- *
- * @throws UnsupportedOperationException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @throws ClassCastException {@inheritDoc}
- * @throws IllegalArgumentException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
- Objects.requireNonNull(function);
- forEach((k,v) -> {
- while (!replace(k, v, function.apply(k, v))) {
- // v changed or k is gone
- if ( (v = get(k)) == null) {
- // k is no longer in the map.
- break;
- }
- }
- });
- }
-
- /**
- * {@inheritDoc}
- *
- * @implSpec
- * The default implementation is equivalent to the following steps for this
- * {@code map}:
- *
- * <pre> {@code
- * V oldValue, newValue;
- * return ((oldValue = map.get(key)) == null
- * && (newValue = mappingFunction.apply(key)) != null
- * && (oldValue = map.putIfAbsent(key, newValue)) == null)
- * ? newValue
- * : oldValue;}</pre>
- *
- * <p>This implementation assumes that the ConcurrentMap cannot contain null
- * values and {@code get()} returning null unambiguously means the key is
- * absent. Implementations which support null values <strong>must</strong>
- * override this default implementation.
- *
- * @throws UnsupportedOperationException {@inheritDoc}
- * @throws ClassCastException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @throws IllegalArgumentException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default V computeIfAbsent(K key,
- Function<? super K, ? extends V> mappingFunction) {
- Objects.requireNonNull(mappingFunction);
- V oldValue, newValue;
- return ((oldValue = get(key)) == null
- && (newValue = mappingFunction.apply(key)) != null
- && (oldValue = putIfAbsent(key, newValue)) == null)
- ? newValue
- : oldValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}:
- *
- * <pre> {@code
- * for (V oldValue; (oldValue = map.get(key)) != null; ) {
- * V newValue = remappingFunction.apply(key, oldValue);
- * if ((newValue == null)
- * ? map.remove(key, oldValue)
- * : map.replace(key, oldValue, newValue))
- * return newValue;
- * }
- * return null;}</pre>
- * When multiple threads attempt updates, map operations and the
- * remapping function may be called multiple times.
- *
- * <p>This implementation assumes that the ConcurrentMap cannot contain null
- * values and {@code get()} returning null unambiguously means the key is
- * absent. Implementations which support null values <strong>must</strong>
- * override this default implementation.
- *
- * @throws UnsupportedOperationException {@inheritDoc}
- * @throws ClassCastException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @throws IllegalArgumentException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default V computeIfPresent(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- Objects.requireNonNull(remappingFunction);
- for (V oldValue; (oldValue = get(key)) != null; ) {
- V newValue = remappingFunction.apply(key, oldValue);
- if ((newValue == null)
- ? remove(key, oldValue)
- : replace(key, oldValue, newValue))
- return newValue;
- }
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}:
- *
- * <pre> {@code
- * for (;;) {
- * V oldValue = map.get(key);
- * V newValue = remappingFunction.apply(key, oldValue);
- * if (newValue != null) {
- * if ((oldValue != null)
- * ? map.replace(key, oldValue, newValue)
- * : map.putIfAbsent(key, newValue) == null)
- * return newValue;
- * } else if (oldValue == null || map.remove(key, oldValue)) {
- * return null;
- * }
- * }}</pre>
- * When multiple threads attempt updates, map operations and the
- * remapping function may be called multiple times.
- *
- * <p>This implementation assumes that the ConcurrentMap cannot contain null
- * values and {@code get()} returning null unambiguously means the key is
- * absent. Implementations which support null values <strong>must</strong>
- * override this default implementation.
- *
- * @throws UnsupportedOperationException {@inheritDoc}
- * @throws ClassCastException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @throws IllegalArgumentException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default V compute(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- retry: for (;;) {
- V oldValue = get(key);
- // if putIfAbsent fails, opportunistically use its return value
- haveOldValue: for (;;) {
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != null) {
- if (oldValue != null) {
- if (replace(key, oldValue, newValue))
- return newValue;
- }
- else if ((oldValue = putIfAbsent(key, newValue)) == null)
- return newValue;
- else continue haveOldValue;
- } else if (oldValue == null || remove(key, oldValue)) {
- return null;
- }
- continue retry;
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}:
- *
- * <pre> {@code
- * for (;;) {
- * V oldValue = map.get(key);
- * if (oldValue != null) {
- * V newValue = remappingFunction.apply(oldValue, value);
- * if (newValue != null) {
- * if (map.replace(key, oldValue, newValue))
- * return newValue;
- * } else if (map.remove(key, oldValue)) {
- * return null;
- * }
- * } else if (map.putIfAbsent(key, value) == null) {
- * return value;
- * }
- * }}</pre>
- * When multiple threads attempt updates, map operations and the
- * remapping function may be called multiple times.
- *
- * <p>This implementation assumes that the ConcurrentMap cannot contain null
- * values and {@code get()} returning null unambiguously means the key is
- * absent. Implementations which support null values <strong>must</strong>
- * override this default implementation.
- *
- * @throws UnsupportedOperationException {@inheritDoc}
- * @throws ClassCastException {@inheritDoc}
- * @throws NullPointerException {@inheritDoc}
- * @throws IllegalArgumentException {@inheritDoc}
- * @since 1.8
- */
- @Override
- default V merge(K key, V value,
- BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
- Objects.requireNonNull(remappingFunction);
- Objects.requireNonNull(value);
- retry: for (;;) {
- V oldValue = get(key);
- // if putIfAbsent fails, opportunistically use its return value
- haveOldValue: for (;;) {
- if (oldValue != null) {
- V newValue = remappingFunction.apply(oldValue, value);
- if (newValue != null) {
- if (replace(key, oldValue, newValue))
- return newValue;
- } else if (remove(key, oldValue)) {
- return null;
- }
- continue retry;
- } else {
- if ((oldValue = putIfAbsent(key, value)) == null)
- return value;
- continue haveOldValue;
- }
- }
- }
- }
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index 0d795b4..17890ff 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -6,8 +6,7 @@
package java.util.concurrent;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
@@ -74,7 +73,7 @@
* reflected in the descending map, and vice-versa.
*
* <p>The returned map has an ordering equivalent to
- * {@link java.util.Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+ * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
* The expression {@code m.descendingMap().descendingMap()} returns a
* view of {@code m} essentially equivalent to {@code m}.
*
@@ -93,12 +92,15 @@
* operations. It does not support the {@code add} or {@code addAll}
* operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* @return a navigable set view of the keys in this map
*/
- NavigableSet<K> navigableKeySet();
+ public NavigableSet<K> navigableKeySet();
/**
* Returns a {@link NavigableSet} view of the keys contained in this map.
@@ -111,8 +113,11 @@
* operations. It does not support the {@code add} or {@code addAll}
* operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* <p>This method is equivalent to method {@code navigableKeySet}.
*
@@ -131,10 +136,13 @@
* operations. It does not support the {@code add} or {@code addAll}
* operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* @return a reverse order navigable set view of the keys in this map
*/
- NavigableSet<K> descendingKeySet();
+ public NavigableSet<K> descendingKeySet();
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index 359d4f1..0e8b64a 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -6,28 +6,7 @@
package java.util.concurrent;
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-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;
-import java.util.SortedMap;
-import java.util.Spliterator;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
@@ -45,13 +24,12 @@
* {@code containsKey}, {@code get}, {@code put} and
* {@code remove} operations and their variants. Insertion, removal,
* update, and access operations safely execute concurrently by
- * multiple threads.
- *
- * <p>Iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>Ascending key ordered views and their iterators are faster than
- * descending ones.
+ * multiple threads. Iterators are <i>weakly consistent</i>, returning
+ * elements reflecting the state of the map at some point at or since
+ * the creation of the iterator. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations. Ascending key ordered views and their iterators
+ * are faster than descending ones.
*
* <p>All {@code Map.Entry} pairs returned by methods in this class
* and its views represent snapshots of mappings at the time they were
@@ -83,8 +61,11 @@
* @param <V> the type of mapped values
* @since 1.6
*/
+@SuppressWarnings("unchecked")
public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
- implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+ implements ConcurrentNavigableMap<K,V>,
+ Cloneable,
+ java.io.Serializable {
/*
* This class implements a tree-like two-dimensionally linked skip
* list in which the index levels are represented in separate
@@ -248,7 +229,7 @@
*
* 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
+ * hardwired parameters k=1, p=0.5 (see method randomLevel) 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
@@ -286,20 +267,6 @@
* 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
@@ -327,10 +294,18 @@
private static final long serialVersionUID = -8627078645895051609L;
+// BEGIN android-removed
+// /**
+// * Generates the initial random seed for the cheaper per-instance
+// * random number generators used in randomLevel.
+// */
+// private static final Random seedGenerator = new Random();
+// END android-removed
+
/**
- * Special value used to identify base-level header.
+ * Special value used to identify base-level header
*/
- static final Object BASE_HEADER = new Object();
+ private static final Object BASE_HEADER = new Object();
/**
* The topmost head index of the skiplist.
@@ -338,19 +313,24 @@
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.)
+ * The comparator used to maintain order in this map, or null
+ * if using natural ordering.
* @serial
*/
- final Comparator<? super K> comparator;
+ private final Comparator<? super K> comparator;
+
+ /**
+ * Seed for simple random number generator. Not volatile since it
+ * doesn't matter too much if different threads don't see updates.
+ */
+ private transient int randomSeed;
/** Lazily initialized key set */
- private transient KeySet<K,V> keySet;
+ private transient KeySet<K> keySet;
/** Lazily initialized entry set */
private transient EntrySet<K,V> entrySet;
/** Lazily initialized values collection */
- private transient Values<K,V> values;
+ private transient Values<V> values;
/** Lazily initialized descending key set */
private transient ConcurrentNavigableMap<K,V> descendingMap;
@@ -359,20 +339,27 @@
* clear, readObject. and ConcurrentSkipListSet.clone.
* (Note that comparator must be separately initialized.)
*/
- private void initialize() {
+ final void initialize() {
keySet = null;
entrySet = null;
values = null;
descendingMap = null;
+ // BEGIN android-changed
+ //
+ // Most processes are forked from the zygote, so they'll end up
+ // with the same random seed unless we take additional post fork
+ // measures.
+ randomSeed = Math.randomIntInternal() | 0x0100; // ensure nonzero
+ // END android-changed
head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
null, null, 1);
}
/**
- * compareAndSet head node.
+ * compareAndSet head node
*/
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
}
/* ---------------- Nodes -------------- */
@@ -412,17 +399,17 @@
}
/**
- * compareAndSet value field.
+ * compareAndSet value field
*/
boolean casValue(Object cmp, Object val) {
- return U.compareAndSwapObject(this, VALUE, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
}
/**
- * compareAndSet next field.
+ * compareAndSet next field
*/
boolean casNext(Node<K,V> cmp, Node<K,V> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
/**
@@ -470,7 +457,7 @@
*/
if (f == next && this == b.next) {
if (f == null || f.value != f) // not already marked
- casNext(f, new Node<K,V>(f));
+ appendMarker(f);
else
b.casNext(this, f.next);
}
@@ -486,8 +473,7 @@
Object v = value;
if (v == this || v == BASE_HEADER)
return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
+ return (V)v;
}
/**
@@ -496,26 +482,27 @@
* @return new entry or null
*/
AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
- Object v = value;
- if (v == null || v == this || v == BASE_HEADER)
+ V v = getValidValue();
+ if (v == null)
return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
}
- // Unsafe mechanics
+ // UNSAFE mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
- private static final long NEXT;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long valueOffset;
+ private static final long nextOffset;
static {
try {
- VALUE = U.objectFieldOffset
- (Node.class.getDeclaredField("value"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Node.class;
+ valueOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("value"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -545,10 +532,10 @@
}
/**
- * compareAndSet right field.
+ * compareAndSet right field
*/
final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
- return U.compareAndSwapObject(this, RIGHT, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val);
}
/**
@@ -581,17 +568,19 @@
* @return true if successful
*/
final boolean unlink(Index<K,V> succ) {
- return node.value != null && casRight(succ, succ.right);
+ return !indexesDeletedNode() && casRight(succ, succ.right);
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long RIGHT;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long rightOffset;
static {
try {
- RIGHT = U.objectFieldOffset
- (Index.class.getDeclaredField("right"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Index.class;
+ rightOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("right"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -613,12 +602,80 @@
/* ---------------- Comparison utilities -------------- */
/**
- * Compares using comparator or natural ordering if null.
- * Called only by methods that have performed required type checks.
+ * Represents a key with a comparator as a Comparable.
+ *
+ * Because most sorted collections seem to use natural ordering on
+ * Comparables (Strings, Integers, etc), most internal methods are
+ * geared to use them. This is generally faster than checking
+ * per-comparison whether to use comparator or comparable because
+ * it doesn't require a (Comparable) cast for each comparison.
+ * (Optimizers can only sometimes remove such redundant checks
+ * themselves.) When Comparators are used,
+ * ComparableUsingComparators are created so that they act in the
+ * same way as natural orderings. This penalizes use of
+ * Comparators vs Comparables, which seems like the right
+ * tradeoff.
*/
- @SuppressWarnings({"unchecked", "rawtypes"})
- static final int cpr(Comparator c, Object x, Object y) {
- return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
+ static final class ComparableUsingComparator<K> implements Comparable<K> {
+ final K actualKey;
+ final Comparator<? super K> cmp;
+ ComparableUsingComparator(K key, Comparator<? super K> cmp) {
+ this.actualKey = key;
+ this.cmp = cmp;
+ }
+ public int compareTo(K k2) {
+ return cmp.compare(actualKey, k2);
+ }
+ }
+
+ /**
+ * If using comparator, return a ComparableUsingComparator, else
+ * cast key as Comparable, which may cause ClassCastException,
+ * which is propagated back to caller.
+ */
+ private Comparable<? super K> comparable(Object key)
+ throws ClassCastException {
+ if (key == null)
+ throw new NullPointerException();
+ if (comparator != null)
+ return new ComparableUsingComparator<K>((K)key, comparator);
+ else
+ return (Comparable<? super K>)key;
+ }
+
+ /**
+ * Compares using comparator or natural ordering. Used when the
+ * ComparableUsingComparator approach doesn't apply.
+ */
+ int compare(K k1, K k2) throws ClassCastException {
+ Comparator<? super K> cmp = comparator;
+ if (cmp != null)
+ return cmp.compare(k1, k2);
+ else
+ return ((Comparable<? super K>)k1).compareTo(k2);
+ }
+
+ /**
+ * Returns true if given key greater than or equal to least and
+ * strictly less than fence, bypassing either test if least or
+ * fence are null. Needed mainly in submap operations.
+ */
+ boolean inHalfOpenRange(K key, K least, K fence) {
+ if (key == null)
+ throw new NullPointerException();
+ return ((least == null || compare(key, least) >= 0) &&
+ (fence == null || compare(key, fence) < 0));
+ }
+
+ /**
+ * Returns true if given key greater than or equal to least and less
+ * or equal to fence. Needed mainly in submap operations.
+ */
+ boolean inOpenRange(K key, K least, K fence) {
+ if (key == null)
+ throw new NullPointerException();
+ return ((least == null || compare(key, least) >= 0) &&
+ (fence == null || compare(key, fence) <= 0));
}
/* ---------------- Traversal -------------- */
@@ -631,11 +688,13 @@
* @param key the key
* @return a predecessor of key
*/
- private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
+ private Node<K,V> findPredecessor(Comparable<? super K> key) {
if (key == null)
throw new NullPointerException(); // don't postpone errors
for (;;) {
- for (Index<K,V> q = head, r = q.right, d;;) {
+ Index<K,V> q = head;
+ Index<K,V> r = q.right;
+ for (;;) {
if (r != null) {
Node<K,V> n = r.node;
K k = n.key;
@@ -645,16 +704,18 @@
r = q.right; // reread r
continue;
}
- if (cpr(cmp, key, k) > 0) {
+ if (key.compareTo(k) > 0) {
q = r;
r = r.right;
continue;
}
}
- if ((d = q.down) == null)
+ Index<K,V> d = q.down;
+ if (d != null) {
+ q = d;
+ r = d.right;
+ } else
return q.node;
- q = d;
- r = d.right;
}
}
}
@@ -695,79 +756,62 @@
*
* 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.
+ * 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
*/
- private Node<K,V> findNode(Object key) {
- if (key == null)
- throw new NullPointerException(); // don't postpone errors
- Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
+ private Node<K,V> findNode(Comparable<? super K> key) {
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
if (n == null)
- break outer;
+ return null;
Node<K,V> f = n.next;
if (n != b.next) // inconsistent read
break;
- if ((v = n.value) == null) { // n is deleted
+ Object v = n.value;
+ if (v == null) { // n is deleted
n.helpDelete(b, f);
break;
}
- if (b.value == null || v == n) // b is deleted
+ if (v == n || b.value == null) // b is deleted
break;
- if ((c = cpr(cmp, key, n.key)) == 0)
+ int c = key.compareTo(n.key);
+ if (c == 0)
return n;
if (c < 0)
- break outer;
+ return null;
b = n;
n = f;
}
}
- return null;
}
/**
- * Gets value for key. Almost the same as findNode, but returns
- * the found value (to avoid retries during re-reads)
- *
- * @param key the key
+ * Gets value for key using findNode.
+ * @param okey the key
* @return the value, or null if absent
*/
- private V doGet(Object key) {
- if (key == null)
- throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- 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;
- }
+ private V doGet(Object okey) {
+ Comparable<? super K> key = comparable(okey);
+ /*
+ * Loop needed here and elsewhere in case value field goes
+ * null just as it is about to be returned, in which case we
+ * lost a race with a deletion, so must retry.
+ */
+ for (;;) {
+ Node<K,V> n = findNode(key);
+ if (n == null)
+ return null;
+ Object v = n.value;
+ if (v != null)
+ return (V)v;
}
- return null;
}
/* ---------------- Insertion -------------- */
@@ -775,126 +819,187 @@
/**
* Main insertion method. Adds element if not present, or
* replaces value if present and onlyIfAbsent is false.
- * @param key the key
+ * @param kkey 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;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+ private V doPut(K kkey, V value, boolean onlyIfAbsent) {
+ Comparable<? super K> key = comparable(kkey);
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
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
+ Object v = n.value;
+ if (v == null) { // n is deleted
n.helpDelete(b, f);
break;
}
- if (b.value == null || v == n) // b is deleted
+ if (v == n || b.value == null) // b is deleted
break;
- if ((c = cpr(cmp, key, n.key)) > 0) {
+ int c = key.compareTo(n.key);
+ if (c > 0) {
b = n;
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
+ if (onlyIfAbsent || n.casValue(v, value))
+ return (V)v;
+ else
+ break; // restart if lost race to replace value
}
// else c < 0; fall through
}
- z = new Node<K,V>(key, value, n);
+ Node<K,V> z = new Node<K,V>(kkey, value, n);
if (!b.casNext(n, z))
break; // restart if lost race to append to b
- break outer;
+ int level = randomLevel();
+ if (level > 0)
+ insertIndex(z, level);
+ return null;
}
}
+ }
- int rnd = ThreadLocalRandom.nextSecondarySeed();
- if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
- int level = 1, max;
- while (((rnd >>>= 1) & 1) != 0)
- ++level;
+ /**
+ * Returns a random level for inserting a new node.
+ * Hardwired to k=1, p=0.5, max 31 (see above and
+ * Pugh's "Skip List Cookbook", sec 3.4).
+ *
+ * This uses the simplest of the generators described in George
+ * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality
+ * generator but is acceptable here.
+ */
+ private int randomLevel() {
+ int x = randomSeed;
+ x ^= x << 13;
+ x ^= x >>> 17;
+ randomSeed = x ^= x << 5;
+ if ((x & 0x80000001) != 0) // test highest and lowest bits
+ return 0;
+ int level = 1;
+ while (((x >>>= 1) & 1) != 0) ++level;
+ return level;
+ }
+
+ /**
+ * Creates and adds index nodes for the given node.
+ * @param z the node
+ * @param level the level of the index
+ */
+ private void insertIndex(Node<K,V> z, int level) {
+ HeadIndex<K,V> h = head;
+ int max = h.level;
+
+ if (level <= max) {
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;
- }
+ for (int i = 1; i <= level; ++i)
+ idx = new Index<K,V>(z, idx, null);
+ addIndex(idx, h, level);
+
+ } else { // Add a new level
+ /*
+ * To reduce interference by other threads checking for
+ * empty levels in tryReduceLevel, new levels are added
+ * with initialized right pointers. Which in turn requires
+ * keeping levels in an array to access them while
+ * creating new head index nodes from the opposite
+ * direction.
+ */
+ level = max + 1;
+ Index<K,V>[] idxs = (Index<K,V>[])new Index<?,?>[level+1];
+ Index<K,V> idx = null;
+ for (int i = 1; i <= level; ++i)
+ idxs[i] = idx = new Index<K,V>(z, idx, null);
+
+ HeadIndex<K,V> oldh;
+ int k;
+ for (;;) {
+ oldh = head;
+ int oldLevel = oldh.level;
+ if (level <= oldLevel) { // lost race to add level
+ k = level;
+ break;
+ }
+ HeadIndex<K,V> newh = oldh;
+ Node<K,V> oldbase = oldh.node;
+ for (int j = oldLevel+1; j <= level; ++j)
+ newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
+ if (casHead(oldh, newh)) {
+ k = oldLevel;
+ break;
}
}
- // 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;
- r = q.right;
- continue;
- }
- if (c > 0) {
- q = r;
- r = r.right;
- continue;
- }
- }
+ addIndex(idxs[k], oldh, k);
+ }
+ }
- if (j == insertionLevel) {
- if (!q.link(r, t))
- break; // restart
- if (t.node.value == null) {
+ /**
+ * Adds given index nodes from given level down to 1.
+ * @param idx the topmost index node being inserted
+ * @param h the value of head to use to insert. This must be
+ * snapshotted by callers to provide correct insertion level.
+ * @param indexLevel the level of the index
+ */
+ private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) {
+ // Track next level to insert in case of retries
+ int insertionLevel = indexLevel;
+ Comparable<? super K> key = comparable(idx.node.key);
+ if (key == null) throw new NullPointerException();
+
+ // Similar to findPredecessor, but adding index nodes along
+ // path to key.
+ for (;;) {
+ int j = h.level;
+ Index<K,V> q = h;
+ Index<K,V> r = q.right;
+ Index<K,V> t = idx;
+ for (;;) {
+ if (r != null) {
+ Node<K,V> n = r.node;
+ // compare before deletion check avoids needing recheck
+ int c = key.compareTo(n.key);
+ if (n.value == null) {
+ if (!q.unlink(r))
+ break;
+ r = q.right;
+ continue;
+ }
+ if (c > 0) {
+ q = r;
+ r = r.right;
+ continue;
+ }
+ }
+
+ if (j == insertionLevel) {
+ // Don't insert index if node already deleted
+ if (t.indexesDeletedNode()) {
+ findNode(key); // cleans up
+ return;
+ }
+ if (!q.link(r, t))
+ break; // restart
+ if (--insertionLevel == 0) {
+ // need final deletion check before return
+ if (t.indexesDeletedNode())
findNode(key);
- break splice;
- }
- if (--insertionLevel == 0)
- break splice;
+ return;
}
-
- if (--j >= insertionLevel && j < level)
- t = t.down;
- q = q.down;
- r = q.right;
}
+
+ if (--j >= insertionLevel && j < indexLevel)
+ t = t.down;
+ q = q.down;
+ r = q.right;
}
}
- return null;
}
/* ---------------- Deletion -------------- */
@@ -913,52 +1018,51 @@
* search for it, and we'd like to ensure lack of garbage
* retention, so must call to be sure.
*
- * @param key the key
+ * @param okey the key
* @param value if non-null, the value that must be
* associated with key
* @return the node, or null if not found
*/
- final V doRemove(Object key, Object value) {
- if (key == null)
- throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
+ final V doRemove(Object okey, Object value) {
+ Comparable<? super K> key = comparable(okey);
+ for (;;) {
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
if (n == null)
- break outer;
+ return null;
Node<K,V> f = n.next;
if (n != b.next) // inconsistent read
break;
- if ((v = n.value) == null) { // n is deleted
+ Object v = n.value;
+ if (v == null) { // n is deleted
n.helpDelete(b, f);
break;
}
- if (b.value == null || v == n) // b is deleted
+ if (v == n || b.value == null) // b is deleted
break;
- if ((c = cpr(cmp, key, n.key)) < 0)
- break outer;
+ int c = key.compareTo(n.key);
+ if (c < 0)
+ return null;
if (c > 0) {
b = n;
n = f;
continue;
}
if (value != null && !value.equals(v))
- break outer;
+ return null;
if (!n.casValue(v, null))
break;
if (!n.appendMarker(f) || !b.casNext(n, f))
- findNode(key); // retry via findNode
+ findNode(key); // Retry via findNode
else {
- findPredecessor(key, cmp); // clean index
+ findPredecessor(key); // Clean index
if (head.right == null)
tryReduceLevel();
}
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
+ return (V)v;
}
}
- return null;
}
/**
@@ -1002,9 +1106,11 @@
* Specialized variant of findNode to get first valid node.
* @return first node or null if empty
*/
- final Node<K,V> findFirst() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
+ Node<K,V> findFirst() {
+ for (;;) {
+ Node<K,V> b = head.node;
+ Node<K,V> n = b.next;
+ if (n == null)
return null;
if (n.value != null)
return n;
@@ -1016,9 +1122,11 @@
* Removes first entry; returns its snapshot.
* @return null if empty, else snapshot of first entry
*/
- private Map.Entry<K,V> doRemoveFirstEntry() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
+ Map.Entry<K,V> doRemoveFirstEntry() {
+ for (;;) {
+ Node<K,V> b = head.node;
+ Node<K,V> n = b.next;
+ if (n == null)
return null;
Node<K,V> f = n.next;
if (n != b.next)
@@ -1033,8 +1141,7 @@
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);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, (V)v);
}
}
@@ -1043,7 +1150,8 @@
*/
private void clearIndexToFirst() {
for (;;) {
- for (Index<K,V> q = head;;) {
+ Index<K,V> q = head;
+ for (;;) {
Index<K,V> r = q.right;
if (r != null && r.indexesDeletedNode() && !q.unlink(r))
break;
@@ -1056,52 +1164,6 @@
}
}
- /**
- * Removes last entry; returns its snapshot.
- * Specialized variant of doRemove.
- * @return null if empty, else snapshot of last entry
- */
- private Map.Entry<K,V> doRemoveLastEntry() {
- 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 (;;) {
- 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 -------------- */
@@ -1109,7 +1171,7 @@
* Specialized version of find to get last valid node.
* @return last node or null if empty
*/
- final Node<K,V> findLast() {
+ Node<K,V> findLast() {
/*
* findPredecessor can't be used to traverse index level
* because this doesn't use comparisons. So traversals of
@@ -1128,7 +1190,9 @@
} else if ((d = q.down) != null) {
q = d;
} else {
- for (Node<K,V> b = q.node, n = b.next;;) {
+ Node<K,V> b = q.node;
+ Node<K,V> n = b.next;
+ for (;;) {
if (n == null)
return b.isBaseHeader() ? null : b;
Node<K,V> f = n.next; // inconsistent read
@@ -1139,7 +1203,7 @@
n.helpDelete(b, f);
break;
}
- if (b.value == null || v == n) // b is deleted
+ if (v == n || b.value == null) // b is deleted
break;
b = n;
n = f;
@@ -1158,7 +1222,8 @@
*/
private Node<K,V> findPredecessorOfLast() {
for (;;) {
- for (Index<K,V> q = head;;) {
+ Index<K,V> q = head;
+ for (;;) {
Index<K,V> d, r;
if ((r = q.right) != null) {
if (r.indexesDeletedNode()) {
@@ -1179,6 +1244,53 @@
}
}
+ /**
+ * Removes last entry; returns its snapshot.
+ * Specialized variant of doRemove.
+ * @return null if empty, else snapshot of last entry
+ */
+ Map.Entry<K,V> doRemoveLastEntry() {
+ 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 (;;) {
+ 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 (v == n || b.value == null) // b is deleted
+ break;
+ if (f != null) {
+ b = n;
+ n = f;
+ continue;
+ }
+ if (!n.casValue(v, null))
+ break;
+ K key = n.key;
+ Comparable<? super K> ck = comparable(key);
+ if (!n.appendMarker(f) || !b.casNext(n, f))
+ findNode(ck); // Retry via findNode
+ else {
+ findPredecessor(ck); // Clean index
+ if (head.right == null)
+ tryReduceLevel();
+ }
+ return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v);
+ }
+ }
+ }
+
/* ---------------- Relational operations -------------- */
// Control values OR'ed as arguments to findNear
@@ -1189,28 +1301,29 @@
/**
* Utility for ceiling, floor, lower, higher methods.
- * @param key the key
+ * @param kkey the key
* @param rel the relation -- OR'ed combination of EQ, LT, GT
* @return nearest node fitting relation, or null if no such
*/
- final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
- if (key == null)
- throw new NullPointerException();
+ Node<K,V> findNear(K kkey, int rel) {
+ Comparable<? super K> key = comparable(kkey);
for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v;
+ Node<K,V> b = findPredecessor(key);
+ Node<K,V> n = b.next;
+ for (;;) {
if (n == null)
return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
Node<K,V> f = n.next;
if (n != b.next) // inconsistent read
break;
- if ((v = n.value) == null) { // n is deleted
+ Object v = n.value;
+ if (v == null) { // n is deleted
n.helpDelete(b, f);
break;
}
- if (b.value == null || v == n) // b is deleted
+ if (v == n || b.value == null) // b is deleted
break;
- int c = cpr(cmp, key, n.key);
+ int c = key.compareTo(n.key);
if ((c == 0 && (rel & EQ) != 0) ||
(c < 0 && (rel & LT) == 0))
return n;
@@ -1228,10 +1341,9 @@
* @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> getNear(K key, int rel) {
- Comparator<? super K> cmp = comparator;
+ AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
for (;;) {
- Node<K,V> n = findNear(key, rel, cmp);
+ Node<K,V> n = findNear(key, rel);
if (n == null)
return null;
AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
@@ -1240,6 +1352,7 @@
}
}
+
/* ---------------- Constructors -------------- */
/**
@@ -1329,7 +1442,7 @@
// 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<>();
+ ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
// initialize
for (int i = 0; i <= h.level; ++i)
@@ -1344,14 +1457,8 @@
map.entrySet().iterator();
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;
- }
+ int j = randomLevel();
+ if (j > h.level) j = h.level + 1;
K k = e.getKey();
V v = e.getValue();
if (k == null || v == null)
@@ -1382,8 +1489,6 @@
/**
* Saves this map to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData The key (Object) and value (Object) for each
* key-value mapping represented by the map, followed by
* {@code null}. The key-value mappings are emitted in key-order
@@ -1408,12 +1513,7 @@
/**
* Reconstitutes this map 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.IOException if an I/O error occurs
*/
- @SuppressWarnings("unchecked")
private void readObject(final java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in the Comparator and any hidden stuff
@@ -1426,12 +1526,12 @@
* 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.
+ * of adaptor 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<>();
+ ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
for (int i = 0; i <= h.level; ++i)
preds.add(null);
Index<K,V> q = h;
@@ -1449,14 +1549,8 @@
throw new NullPointerException();
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;
- }
+ int j = randomLevel();
+ if (j > h.level) j = h.level + 1;
Node<K,V> z = new Node<K,V>(key, val, null);
basepred.next = z;
basepred = z;
@@ -1513,22 +1607,6 @@
}
/**
- * Returns the value to which the specified key is mapped,
- * or the given defaultValue if this map contains no mapping for the key.
- *
- * @param key the key
- * @param defaultValue the value to return if this map contains
- * no mapping for the given key
- * @return the mapping for the key, if present; else the defaultValue
- * @throws NullPointerException if the specified key is null
- * @since 1.8
- */
- public V getOrDefault(Object key, V defaultValue) {
- V v;
- return (v = doGet(key)) == null ? defaultValue : v;
- }
-
- /**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
@@ -1624,140 +1702,6 @@
initialize();
}
- /**
- * If the specified key is not already associated with a value,
- * attempts to compute its value using the given mapping function
- * and enters it into this map unless {@code null}. The function
- * is <em>NOT</em> guaranteed to be applied once atomically only
- * if the value is not present.
- *
- * @param key key with which the specified value is to be associated
- * @param mappingFunction the function to compute a value
- * @return the current (existing or computed) value associated with
- * the specified key, or null if the computed value is null
- * @throws NullPointerException if the specified key is null
- * or the mappingFunction is null
- * @since 1.8
- */
- public V computeIfAbsent(K key,
- Function<? super K, ? extends V> mappingFunction) {
- if (key == null || mappingFunction == null)
- throw new NullPointerException();
- V v, p, r;
- if ((v = doGet(key)) == null &&
- (r = mappingFunction.apply(key)) != null)
- v = (p = doPut(key, r, true)) == null ? r : p;
- return v;
- }
-
- /**
- * If the value for the specified key is present, attempts to
- * compute a new mapping given the key and its current mapped
- * value. The function is <em>NOT</em> guaranteed to be applied
- * once atomically.
- *
- * @param key key with which a value may be associated
- * @param remappingFunction the function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key is null
- * or the remappingFunction is null
- * @since 1.8
- */
- public V computeIfPresent(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (key == null || remappingFunction == null)
- throw new NullPointerException();
- Node<K,V> n; Object v;
- while ((n = findNode(key)) != null) {
- if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- V r = remappingFunction.apply(key, vv);
- if (r != null) {
- if (n.casValue(vv, r))
- return r;
- }
- else if (doRemove(key, vv) != null)
- break;
- }
- }
- return null;
- }
-
- /**
- * Attempts to compute a mapping for the specified key and its
- * current mapped value (or {@code null} if there is no current
- * mapping). The function is <em>NOT</em> guaranteed to be applied
- * once atomically.
- *
- * @param key key with which the specified value is to be associated
- * @param remappingFunction the function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key is null
- * or the remappingFunction is null
- * @since 1.8
- */
- public V compute(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (key == null || remappingFunction == null)
- throw new NullPointerException();
- for (;;) {
- 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.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, vv) != null)
- break;
- }
- }
- return null;
- }
-
- /**
- * If the specified key is not already associated with a value,
- * associates it with the given value. Otherwise, replaces the
- * value with the results of the given remapping function, or
- * removes if {@code null}. The function is <em>NOT</em>
- * guaranteed to be applied once atomically.
- *
- * @param key key with which the specified value is to be associated
- * @param value the value to use if absent
- * @param remappingFunction the function to recompute a value if present
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key or value is null
- * or the remappingFunction is null
- * @since 1.8
- */
- public V merge(K key, V value,
- BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
- if (key == null || value == null || remappingFunction == null)
- throw new NullPointerException();
- for (;;) {
- 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.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, vv) != null)
- return null;
- }
- }
- }
-
/* ---------------- View methods -------------- */
/*
@@ -1771,18 +1715,8 @@
/**
* Returns a {@link NavigableSet} view of the keys contained in this map.
- *
- * <p>The set's iterator returns the keys in ascending order.
- * 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. 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.
- *
- * <p>The set is backed by the map, so changes to the map are
+ * The set's iterator returns the keys in ascending order.
+ * The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. The set supports element
* removal, which removes the corresponding mapping from the map,
* via the {@code Iterator.remove}, {@code Set.remove},
@@ -1790,32 +1724,31 @@
* operations. It does not support the {@code add} or {@code addAll}
* operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
* <p>This method is equivalent to method {@code navigableKeySet}.
*
* @return a navigable set view of the keys in this map
*/
public NavigableSet<K> keySet() {
- KeySet<K,V> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<>(this));
+ KeySet<K> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet<K>(this));
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K,V> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<>(this));
+ KeySet<K> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet<K>(this));
}
/**
* Returns a {@link Collection} view of the values contained in this map.
- * <p>The collection's iterator returns the values in ascending order
- * of the corresponding keys. The collections's spliterator additionally
- * reports {@link Spliterator#CONCURRENT}, {@link Spliterator#NONNULL} and
- * {@link Spliterator#ORDERED}, with an encounter order that is ascending
- * order of the corresponding keys.
- *
- * <p>The collection is backed by the map, so changes to the map are
+ * The collection's iterator returns the values in ascending order
+ * of the corresponding keys.
+ * The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. The collection
* supports element removal, which removes the corresponding
* mapping from the map, via the {@code Iterator.remove},
@@ -1823,24 +1756,21 @@
* {@code retainAll} and {@code clear} operations. It does not
* support the {@code add} or {@code addAll} operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*/
public Collection<V> values() {
- Values<K,V> vs = values;
- return (vs != null) ? vs : (values = new Values<>(this));
+ Values<V> vs = values;
+ return (vs != null) ? vs : (values = new Values<V>(this));
}
/**
* Returns a {@link Set} view of the mappings contained in this map.
- *
- * <p>The set's iterator returns the entries in ascending key order. 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 set is backed by the map, so changes to the map are
+ * The set's iterator returns the entries in ascending key order.
+ * The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. The set supports element
* removal, which removes the corresponding mapping from the map,
* via the {@code Iterator.remove}, {@code Set.remove},
@@ -1848,12 +1778,15 @@
* operations. It does not support the {@code add} or
* {@code addAll} operations.
*
- * <p>The view's iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
*
- * <p>The {@code Map.Entry} elements traversed by the {@code iterator}
- * or {@code spliterator} do <em>not</em> support the {@code setValue}
- * operation.
+ * <p>The {@code Map.Entry} elements returned by
+ * {@code iterator.next()} do <em>not</em> support the
+ * {@code setValue} operation.
*
* @return a set view of the mappings contained in this map,
* sorted in ascending key order
@@ -1938,7 +1871,9 @@
public boolean remove(Object key, Object value) {
if (key == null)
throw new NullPointerException();
- return value != null && doRemove(key, value) != null;
+ if (value == null)
+ return false;
+ return doRemove(key, value) != null;
}
/**
@@ -1949,13 +1884,15 @@
* @throws NullPointerException if any of the arguments are null
*/
public boolean replace(K key, V oldValue, V newValue) {
- if (key == null || oldValue == null || newValue == null)
+ if (oldValue == null || newValue == null)
throw new NullPointerException();
+ Comparable<? super K> k = comparable(key);
for (;;) {
- Node<K,V> n; Object v;
- if ((n = findNode(key)) == null)
+ Node<K,V> n = findNode(k);
+ if (n == null)
return false;
- if ((v = n.value) != null) {
+ Object v = n.value;
+ if (v != null) {
if (!oldValue.equals(v))
return false;
if (n.casValue(v, newValue))
@@ -1974,16 +1911,16 @@
* @throws NullPointerException if the specified key or value is null
*/
public V replace(K key, V value) {
- if (key == null || value == null)
+ if (value == null)
throw new NullPointerException();
+ Comparable<? super K> k = comparable(key);
for (;;) {
- Node<K,V> n; Object v;
- if ((n = findNode(key)) == null)
+ Node<K,V> n = findNode(k);
+ if (n == null)
return null;
- if ((v = n.value) != null && n.casValue(v, value)) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
+ Object v = n.value;
+ if (v != null && n.casValue(v, value))
+ return (V)v;
}
}
@@ -2101,7 +2038,7 @@
* @throws NullPointerException if the specified key is null
*/
public K lowerKey(K key) {
- Node<K,V> n = findNear(key, LT, comparator);
+ Node<K,V> n = findNear(key, LT);
return (n == null) ? null : n.key;
}
@@ -2125,7 +2062,7 @@
* @throws NullPointerException if the specified key is null
*/
public K floorKey(K key) {
- Node<K,V> n = findNear(key, LT|EQ, comparator);
+ Node<K,V> n = findNear(key, LT|EQ);
return (n == null) ? null : n.key;
}
@@ -2147,7 +2084,7 @@
* @throws NullPointerException if the specified key is null
*/
public K ceilingKey(K key) {
- Node<K,V> n = findNear(key, GT|EQ, comparator);
+ Node<K,V> n = findNear(key, GT|EQ);
return (n == null) ? null : n.key;
}
@@ -2171,7 +2108,7 @@
* @throws NullPointerException if the specified key is null
*/
public K higherKey(K key) {
- Node<K,V> n = findNear(key, GT, comparator);
+ Node<K,V> n = findNear(key, GT);
return (n == null) ? null : n.key;
}
@@ -2245,11 +2182,13 @@
/** Initializes ascending iterator for entire range. */
Iter() {
- while ((next = findFirst()) != null) {
+ for (;;) {
+ next = findFirst();
+ if (next == null)
+ break;
Object x = next.value;
if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
+ nextValue = (V) x;
break;
}
}
@@ -2264,11 +2203,13 @@
if (next == null)
throw new NoSuchElementException();
lastReturned = next;
- while ((next = next.next) != null) {
+ for (;;) {
+ next = next.next;
+ if (next == null)
+ break;
Object x = next.value;
if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
+ nextValue = (V) x;
break;
}
}
@@ -2311,6 +2252,20 @@
}
}
+ // Factory methods for iterators needed by ConcurrentSkipListSet etc
+
+ Iterator<K> keyIterator() {
+ return new KeyIterator();
+ }
+
+ Iterator<V> valueIterator() {
+ return new ValueIterator();
+ }
+
+ Iterator<Map.Entry<K,V>> entryIterator() {
+ return new EntryIterator();
+ }
+
/* ---------------- View Classes -------------- */
/*
@@ -2327,34 +2282,35 @@
return list;
}
- static final class KeySet<K,V>
- extends AbstractSet<K> implements NavigableSet<K> {
- final ConcurrentNavigableMap<K,V> m;
- KeySet(ConcurrentNavigableMap<K,V> map) { m = map; }
+ static final class KeySet<E>
+ extends AbstractSet<E> implements NavigableSet<E> {
+ private final ConcurrentNavigableMap<E,?> m;
+ KeySet(ConcurrentNavigableMap<E,?> map) { m = map; }
public int size() { return m.size(); }
public boolean isEmpty() { return m.isEmpty(); }
public boolean contains(Object o) { return m.containsKey(o); }
public boolean remove(Object o) { return m.remove(o) != null; }
public void clear() { m.clear(); }
- public K lower(K e) { return m.lowerKey(e); }
- public K floor(K e) { return m.floorKey(e); }
- public K ceiling(K e) { return m.ceilingKey(e); }
- public K higher(K e) { return m.higherKey(e); }
- public Comparator<? super K> comparator() { return m.comparator(); }
- public K first() { return m.firstKey(); }
- public K last() { return m.lastKey(); }
- public K pollFirst() {
- Map.Entry<K,V> e = m.pollFirstEntry();
+ public E lower(E e) { return m.lowerKey(e); }
+ public E floor(E e) { return m.floorKey(e); }
+ public E ceiling(E e) { return m.ceilingKey(e); }
+ public E higher(E e) { return m.higherKey(e); }
+ public Comparator<? super E> comparator() { return m.comparator(); }
+ public E first() { return m.firstKey(); }
+ public E last() { return m.lastKey(); }
+ public E pollFirst() {
+ Map.Entry<E,?> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
- public K pollLast() {
- Map.Entry<K,V> e = m.pollLastEntry();
+ public E pollLast() {
+ Map.Entry<E,?> e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
- public Iterator<K> iterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).new KeyIterator()
- : ((SubMap<K,V>)m).new SubMapKeyIterator();
+ public Iterator<E> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<E,Object>)m).keyIterator();
+ else
+ return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator();
}
public boolean equals(Object o) {
if (o == this)
@@ -2372,99 +2328,81 @@
}
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
- public Iterator<K> descendingIterator() {
+ public Iterator<E> descendingIterator() {
return descendingSet().iterator();
}
- public NavigableSet<K> subSet(K fromElement,
+ public NavigableSet<E> subSet(E fromElement,
boolean fromInclusive,
- K toElement,
+ E toElement,
boolean toInclusive) {
- return new KeySet<>(m.subMap(fromElement, fromInclusive,
- toElement, toInclusive));
+ return new KeySet<E>(m.subMap(fromElement, fromInclusive,
+ toElement, toInclusive));
}
- public NavigableSet<K> headSet(K toElement, boolean inclusive) {
- return new KeySet<>(m.headMap(toElement, inclusive));
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new KeySet<E>(m.headMap(toElement, inclusive));
}
- public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
- return new KeySet<>(m.tailMap(fromElement, inclusive));
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return new KeySet<E>(m.tailMap(fromElement, inclusive));
}
- public NavigableSet<K> subSet(K fromElement, K toElement) {
+ public NavigableSet<E> subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
- public NavigableSet<K> headSet(K toElement) {
+ public NavigableSet<E> headSet(E toElement) {
return headSet(toElement, false);
}
- public NavigableSet<K> tailSet(K fromElement) {
+ public NavigableSet<E> tailSet(E fromElement) {
return tailSet(fromElement, true);
}
- public NavigableSet<K> descendingSet() {
- return new KeySet<>(m.descendingMap());
- }
-
- public Spliterator<K> spliterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
- : ((SubMap<K,V>)m).new SubMapKeyIterator();
+ public NavigableSet<E> descendingSet() {
+ return new KeySet<E>(m.descendingMap());
}
}
- static final class Values<K,V> extends AbstractCollection<V> {
- final ConcurrentNavigableMap<K,V> m;
- Values(ConcurrentNavigableMap<K,V> map) {
+ static final class Values<E> extends AbstractCollection<E> {
+ private final ConcurrentNavigableMap<?,E> m;
+ Values(ConcurrentNavigableMap<?,E> map) {
m = map;
}
- public Iterator<V> iterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
- : ((SubMap<K,V>)m).new SubMapValueIterator();
+ public Iterator<E> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<?,E>)m).valueIterator();
+ else
+ return ((SubMap<?,E>)m).valueIterator();
}
- public int size() { return m.size(); }
- public boolean isEmpty() { return m.isEmpty(); }
- public boolean contains(Object o) { return m.containsValue(o); }
- public void clear() { m.clear(); }
+ public boolean isEmpty() {
+ return m.isEmpty();
+ }
+ public int size() {
+ return m.size();
+ }
+ public boolean contains(Object o) {
+ return m.containsValue(o);
+ }
+ public void clear() {
+ m.clear();
+ }
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
-
- public Spliterator<V> spliterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).valueSpliterator()
- : ((SubMap<K,V>)m).new SubMapValueIterator();
- }
-
- public boolean removeIf(Predicate<? super V> filter) {
- if (filter == null) throw new NullPointerException();
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<K,V>)m).removeValueIf(filter);
- // else use iterator
- Iterator<Map.Entry<K,V>> it =
- ((SubMap<K,V>)m).new SubMapEntryIterator();
- boolean removed = false;
- while (it.hasNext()) {
- Map.Entry<K,V> e = it.next();
- V v = e.getValue();
- if (filter.test(v) && m.remove(e.getKey(), v))
- removed = true;
- }
- return removed;
- }
}
- static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
- final ConcurrentNavigableMap<K,V> m;
- EntrySet(ConcurrentNavigableMap<K,V> map) {
+ static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> {
+ private final ConcurrentNavigableMap<K1, V1> m;
+ EntrySet(ConcurrentNavigableMap<K1, V1> map) {
m = map;
}
- public Iterator<Map.Entry<K,V>> iterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).new EntryIterator()
- : ((SubMap<K,V>)m).new SubMapEntryIterator();
+
+ public Iterator<Map.Entry<K1,V1>> iterator() {
+ if (m instanceof ConcurrentSkipListMap)
+ return ((ConcurrentSkipListMap<K1,V1>)m).entryIterator();
+ else
+ return ((SubMap<K1,V1>)m).entryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- V v = m.get(e.getKey());
+ V1 v = m.get(e.getKey());
return v != null && v.equals(e.getValue());
}
public boolean remove(Object o) {
@@ -2499,47 +2437,27 @@
}
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
-
- public Spliterator<Map.Entry<K,V>> spliterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<K,V>)m).entrySpliterator()
- : ((SubMap<K,V>)m).new SubMapEntryIterator();
- }
- public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
- if (filter == null) throw new NullPointerException();
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<K,V>)m).removeEntryIf(filter);
- // else use iterator
- Iterator<Map.Entry<K,V>> it =
- ((SubMap<K,V>)m).new SubMapEntryIterator();
- boolean removed = false;
- while (it.hasNext()) {
- Map.Entry<K,V> e = it.next();
- if (filter.test(e) && m.remove(e.getKey(), e.getValue()))
- removed = true;
- }
- return removed;
- }
}
/**
* Submaps returned by {@link ConcurrentSkipListMap} submap operations
- * represent a subrange of mappings of their underlying maps.
- * Instances of this class support all methods of their underlying
- * maps, differing in that mappings outside their range are ignored,
- * and attempts to add mappings outside their ranges result in {@link
- * IllegalArgumentException}. Instances of this class are constructed
- * only using the {@code subMap}, {@code headMap}, and {@code tailMap}
- * methods of their underlying maps.
+ * represent a subrange of mappings of their underlying
+ * maps. Instances of this class support all methods of their
+ * underlying maps, differing in that mappings outside their range are
+ * ignored, and attempts to add mappings outside their ranges result
+ * in {@link IllegalArgumentException}. Instances of this class are
+ * constructed only using the {@code subMap}, {@code headMap}, and
+ * {@code tailMap} methods of their underlying maps.
*
* @serial include
*/
static final class SubMap<K,V> extends AbstractMap<K,V>
- implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+ implements ConcurrentNavigableMap<K,V>, Cloneable,
+ java.io.Serializable {
private static final long serialVersionUID = -7647078645895051609L;
/** Underlying map */
- final ConcurrentSkipListMap<K,V> m;
+ private final ConcurrentSkipListMap<K,V> m;
/** lower bound key, or null if from start */
private final K lo;
/** upper bound key, or null if to end */
@@ -2549,10 +2467,10 @@
/** inclusion flag for hi */
private final boolean hiInclusive;
/** direction */
- final boolean isDescending;
+ private final boolean isDescending;
// Lazily initialized view holders
- private transient KeySet<K,V> keySetView;
+ private transient KeySet<K> keySetView;
private transient Set<Map.Entry<K,V>> entrySetView;
private transient Collection<V> valuesView;
@@ -2563,9 +2481,8 @@
K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive,
boolean isDescending) {
- Comparator<? super K> cmp = map.comparator;
if (fromKey != null && toKey != null &&
- cpr(cmp, fromKey, toKey) > 0)
+ map.compare(fromKey, toKey) > 0)
throw new IllegalArgumentException("inconsistent range");
this.m = map;
this.lo = fromKey;
@@ -2577,34 +2494,39 @@
/* ---------------- Utilities -------------- */
- boolean tooLow(Object key, Comparator<? super K> cmp) {
- int c;
- return (lo != null && ((c = cpr(cmp, key, lo)) < 0 ||
- (c == 0 && !loInclusive)));
+ private boolean tooLow(K key) {
+ if (lo != null) {
+ int c = m.compare(key, lo);
+ if (c < 0 || (c == 0 && !loInclusive))
+ return true;
+ }
+ return false;
}
- boolean tooHigh(Object key, Comparator<? super K> cmp) {
- int c;
- return (hi != null && ((c = cpr(cmp, key, hi)) > 0 ||
- (c == 0 && !hiInclusive)));
+ private boolean tooHigh(K key) {
+ if (hi != null) {
+ int c = m.compare(key, hi);
+ if (c > 0 || (c == 0 && !hiInclusive))
+ return true;
+ }
+ return false;
}
- boolean inBounds(Object key, Comparator<? super K> cmp) {
- return !tooLow(key, cmp) && !tooHigh(key, cmp);
+ private boolean inBounds(K key) {
+ return !tooLow(key) && !tooHigh(key);
}
- void checkKeyBounds(K key, Comparator<? super K> cmp) {
+ private void checkKeyBounds(K key) throws IllegalArgumentException {
if (key == null)
throw new NullPointerException();
- if (!inBounds(key, cmp))
+ if (!inBounds(key))
throw new IllegalArgumentException("key out of range");
}
/**
* Returns true if node key is less than upper bound of range.
*/
- boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n,
- Comparator<? super K> cmp) {
+ private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) {
if (n == null)
return false;
if (hi == null)
@@ -2612,7 +2534,7 @@
K k = n.key;
if (k == null) // pass by markers and headers
return true;
- int c = cpr(cmp, k, hi);
+ int c = m.compare(k, hi);
if (c > 0 || (c == 0 && !hiInclusive))
return false;
return true;
@@ -2622,35 +2544,34 @@
* Returns lowest node. This node might not be in range, so
* most usages need to check bounds.
*/
- ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) {
+ private ConcurrentSkipListMap.Node<K,V> loNode() {
if (lo == null)
return m.findFirst();
else if (loInclusive)
- return m.findNear(lo, GT|EQ, cmp);
+ return m.findNear(lo, GT|EQ);
else
- return m.findNear(lo, GT, cmp);
+ return m.findNear(lo, GT);
}
/**
* Returns highest node. This node might not be in range, so
* most usages need to check bounds.
*/
- ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) {
+ private ConcurrentSkipListMap.Node<K,V> hiNode() {
if (hi == null)
return m.findLast();
else if (hiInclusive)
- return m.findNear(hi, LT|EQ, cmp);
+ return m.findNear(hi, LT|EQ);
else
- return m.findNear(hi, LT, cmp);
+ return m.findNear(hi, LT);
}
/**
* Returns lowest absolute key (ignoring directionality).
*/
- K lowestKey() {
- Comparator<? super K> cmp = m.comparator;
- ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- if (isBeforeEnd(n, cmp))
+ private K lowestKey() {
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (isBeforeEnd(n))
return n.key;
else
throw new NoSuchElementException();
@@ -2659,22 +2580,20 @@
/**
* Returns highest absolute key (ignoring directionality).
*/
- K highestKey() {
- Comparator<? super K> cmp = m.comparator;
- ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+ private K highestKey() {
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
if (n != null) {
K last = n.key;
- if (inBounds(last, cmp))
+ if (inBounds(last))
return last;
}
throw new NoSuchElementException();
}
- Map.Entry<K,V> lowestEntry() {
- Comparator<? super K> cmp = m.comparator;
+ private Map.Entry<K,V> lowestEntry() {
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- if (!isBeforeEnd(n, cmp))
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (!isBeforeEnd(n))
return null;
Map.Entry<K,V> e = n.createSnapshot();
if (e != null)
@@ -2682,11 +2601,10 @@
}
}
- Map.Entry<K,V> highestEntry() {
- Comparator<? super K> cmp = m.comparator;
+ private Map.Entry<K,V> highestEntry() {
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
- if (n == null || !inBounds(n.key, cmp))
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
+ if (n == null || !inBounds(n.key))
return null;
Map.Entry<K,V> e = n.createSnapshot();
if (e != null)
@@ -2694,14 +2612,13 @@
}
}
- Map.Entry<K,V> removeLowest() {
- Comparator<? super K> cmp = m.comparator;
+ private Map.Entry<K,V> removeLowest() {
for (;;) {
- Node<K,V> n = loNode(cmp);
+ Node<K,V> n = loNode();
if (n == null)
return null;
K k = n.key;
- if (!inBounds(k, cmp))
+ if (!inBounds(k))
return null;
V v = m.doRemove(k, null);
if (v != null)
@@ -2709,14 +2626,13 @@
}
}
- Map.Entry<K,V> removeHighest() {
- Comparator<? super K> cmp = m.comparator;
+ private Map.Entry<K,V> removeHighest() {
for (;;) {
- Node<K,V> n = hiNode(cmp);
+ Node<K,V> n = hiNode();
if (n == null)
return null;
K k = n.key;
- if (!inBounds(k, cmp))
+ if (!inBounds(k))
return null;
V v = m.doRemove(k, null);
if (v != null)
@@ -2725,23 +2641,22 @@
}
/**
- * Submap version of ConcurrentSkipListMap.getNearEntry.
+ * Submap version of ConcurrentSkipListMap.getNearEntry
*/
- Map.Entry<K,V> getNearEntry(K key, int rel) {
- Comparator<? super K> cmp = m.comparator;
+ private Map.Entry<K,V> getNearEntry(K key, int rel) {
if (isDescending) { // adjust relation for direction
if ((rel & LT) == 0)
rel |= LT;
else
rel &= ~LT;
}
- if (tooLow(key, cmp))
+ if (tooLow(key))
return ((rel & LT) != 0) ? null : lowestEntry();
- if (tooHigh(key, cmp))
+ if (tooHigh(key))
return ((rel & LT) != 0) ? highestEntry() : null;
for (;;) {
- Node<K,V> n = m.findNear(key, rel, cmp);
- if (n == null || !inBounds(n.key, cmp))
+ Node<K,V> n = m.findNear(key, rel);
+ if (n == null || !inBounds(n.key))
return null;
K k = n.key;
V v = n.getValidValue();
@@ -2751,36 +2666,35 @@
}
// Almost the same as getNearEntry, except for keys
- K getNearKey(K key, int rel) {
- Comparator<? super K> cmp = m.comparator;
+ private K getNearKey(K key, int rel) {
if (isDescending) { // adjust relation for direction
if ((rel & LT) == 0)
rel |= LT;
else
rel &= ~LT;
}
- if (tooLow(key, cmp)) {
+ if (tooLow(key)) {
if ((rel & LT) == 0) {
- ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- if (isBeforeEnd(n, cmp))
+ ConcurrentSkipListMap.Node<K,V> n = loNode();
+ if (isBeforeEnd(n))
return n.key;
}
return null;
}
- if (tooHigh(key, cmp)) {
+ if (tooHigh(key)) {
if ((rel & LT) != 0) {
- ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+ ConcurrentSkipListMap.Node<K,V> n = hiNode();
if (n != null) {
K last = n.key;
- if (inBounds(last, cmp))
+ if (inBounds(last))
return last;
}
}
return null;
}
for (;;) {
- Node<K,V> n = m.findNear(key, rel, cmp);
- if (n == null || !inBounds(n.key, cmp))
+ Node<K,V> n = m.findNear(key, rel);
+ if (n == null || !inBounds(n.key))
return null;
K k = n.key;
V v = n.getValidValue();
@@ -2793,28 +2707,30 @@
public boolean containsKey(Object key) {
if (key == null) throw new NullPointerException();
- return inBounds(key, m.comparator) && m.containsKey(key);
+ K k = (K)key;
+ return inBounds(k) && m.containsKey(k);
}
public V get(Object key) {
if (key == null) throw new NullPointerException();
- return (!inBounds(key, m.comparator)) ? null : m.get(key);
+ K k = (K)key;
+ return (!inBounds(k)) ? null : m.get(k);
}
public V put(K key, V value) {
- checkKeyBounds(key, m.comparator);
+ checkKeyBounds(key);
return m.put(key, value);
}
public V remove(Object key) {
- return (!inBounds(key, m.comparator)) ? null : m.remove(key);
+ K k = (K)key;
+ return (!inBounds(k)) ? null : m.remove(k);
}
public int size() {
- Comparator<? super K> cmp = m.comparator;
long count = 0;
- for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- isBeforeEnd(n, cmp);
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
n = n.next) {
if (n.getValidValue() != null)
++count;
@@ -2823,16 +2739,14 @@
}
public boolean isEmpty() {
- Comparator<? super K> cmp = m.comparator;
- return !isBeforeEnd(loNode(cmp), cmp);
+ return !isBeforeEnd(loNode());
}
public boolean containsValue(Object value) {
if (value == null)
throw new NullPointerException();
- Comparator<? super K> cmp = m.comparator;
- for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- isBeforeEnd(n, cmp);
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
n = n.next) {
V v = n.getValidValue();
if (v != null && value.equals(v))
@@ -2842,9 +2756,8 @@
}
public void clear() {
- Comparator<? super K> cmp = m.comparator;
- for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- isBeforeEnd(n, cmp);
+ for (ConcurrentSkipListMap.Node<K,V> n = loNode();
+ isBeforeEnd(n);
n = n.next) {
if (n.getValidValue() != null)
m.remove(n.key);
@@ -2854,21 +2767,22 @@
/* ---------------- ConcurrentMap API methods -------------- */
public V putIfAbsent(K key, V value) {
- checkKeyBounds(key, m.comparator);
+ checkKeyBounds(key);
return m.putIfAbsent(key, value);
}
public boolean remove(Object key, Object value) {
- return inBounds(key, m.comparator) && m.remove(key, value);
+ K k = (K)key;
+ return inBounds(k) && m.remove(k, value);
}
public boolean replace(K key, V oldValue, V newValue) {
- checkKeyBounds(key, m.comparator);
+ checkKeyBounds(key);
return m.replace(key, oldValue, newValue);
}
public V replace(K key, V value) {
- checkKeyBounds(key, m.comparator);
+ checkKeyBounds(key);
return m.replace(key, value);
}
@@ -2886,9 +2800,10 @@
* Utility to create submaps, where given bounds override
* unbounded(null) ones and/or are checked against bounded ones.
*/
- SubMap<K,V> newSubMap(K fromKey, boolean fromInclusive,
- K toKey, boolean toInclusive) {
- Comparator<? super K> cmp = m.comparator;
+ private SubMap<K,V> newSubMap(K fromKey,
+ boolean fromInclusive,
+ K toKey,
+ boolean toInclusive) {
if (isDescending) { // flip senses
K tk = fromKey;
fromKey = toKey;
@@ -2903,7 +2818,7 @@
fromInclusive = loInclusive;
}
else {
- int c = cpr(cmp, fromKey, lo);
+ int c = m.compare(fromKey, lo);
if (c < 0 || (c == 0 && !loInclusive && fromInclusive))
throw new IllegalArgumentException("key out of range");
}
@@ -2914,7 +2829,7 @@
toInclusive = hiInclusive;
}
else {
- int c = cpr(cmp, toKey, hi);
+ int c = m.compare(toKey, hi);
if (c > 0 || (c == 0 && !hiInclusive && toInclusive))
throw new IllegalArgumentException("key out of range");
}
@@ -2923,20 +2838,24 @@
toKey, toInclusive, isDescending);
}
- public SubMap<K,V> subMap(K fromKey, boolean fromInclusive,
- K toKey, boolean toInclusive) {
+ public SubMap<K,V> subMap(K fromKey,
+ boolean fromInclusive,
+ K toKey,
+ boolean toInclusive) {
if (fromKey == null || toKey == null)
throw new NullPointerException();
return newSubMap(fromKey, fromInclusive, toKey, toInclusive);
}
- public SubMap<K,V> headMap(K toKey, boolean inclusive) {
+ public SubMap<K,V> headMap(K toKey,
+ boolean inclusive) {
if (toKey == null)
throw new NullPointerException();
return newSubMap(null, false, toKey, inclusive);
}
- public SubMap<K,V> tailMap(K fromKey, boolean inclusive) {
+ public SubMap<K,V> tailMap(K fromKey,
+ boolean inclusive) {
if (fromKey == null)
throw new NullPointerException();
return newSubMap(fromKey, inclusive, null, false);
@@ -3020,18 +2939,18 @@
/* ---------------- Submap Views -------------- */
public NavigableSet<K> keySet() {
- KeySet<K,V> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+ KeySet<K> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K,V> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+ KeySet<K> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
}
public Collection<V> values() {
Collection<V> vs = valuesView;
- return (vs != null) ? vs : (valuesView = new Values<>(this));
+ return (vs != null) ? vs : (valuesView = new Values<V>(this));
}
public Set<Map.Entry<K,V>> entrySet() {
@@ -3043,11 +2962,22 @@
return descendingMap().navigableKeySet();
}
+ Iterator<K> keyIterator() {
+ return new SubMapKeyIterator();
+ }
+
+ Iterator<V> valueIterator() {
+ return new SubMapValueIterator();
+ }
+
+ Iterator<Map.Entry<K,V>> entryIterator() {
+ return new SubMapEntryIterator();
+ }
+
/**
* Variant of main Iter class to traverse through submaps.
- * Also serves as back-up Spliterator for views.
*/
- abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
+ abstract class SubMapIter<T> implements Iterator<T> {
/** the last node returned by next() */
Node<K,V> lastReturned;
/** the next node to return from next(); */
@@ -3056,19 +2986,16 @@
V nextValue;
SubMapIter() {
- Comparator<? super K> cmp = m.comparator;
for (;;) {
- next = isDescending ? hiNode(cmp) : loNode(cmp);
+ next = isDescending ? hiNode() : loNode();
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) {
- if (! inBounds(next.key, cmp))
+ if (! inBounds(next.key))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = (V) x;
break;
}
}
@@ -3089,38 +3016,32 @@
}
private void ascend() {
- Comparator<? super K> cmp = m.comparator;
for (;;) {
next = next.next;
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) {
- if (tooHigh(next.key, cmp))
+ if (tooHigh(next.key))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = (V) x;
break;
}
}
}
private void descend() {
- Comparator<? super K> cmp = m.comparator;
for (;;) {
- next = m.findNear(lastReturned.key, LT, cmp);
+ next = m.findNear(lastReturned.key, LT);
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) {
- if (tooLow(next.key, cmp))
+ if (tooLow(next.key))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = (V) x;
break;
}
}
@@ -3134,27 +3055,6 @@
lastReturned = null;
}
- public Spliterator<T> trySplit() {
- return null;
- }
-
- public boolean tryAdvance(Consumer<? super T> action) {
- if (hasNext()) {
- action.accept(next());
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(Consumer<? super T> action) {
- while (hasNext())
- action.accept(next());
- }
-
- public long estimateSize() {
- return Long.MAX_VALUE;
- }
-
}
final class SubMapValueIterator extends SubMapIter<V> {
@@ -3163,9 +3063,6 @@
advance();
return v;
}
- public int characteristics() {
- return 0;
- }
}
final class SubMapKeyIterator extends SubMapIter<K> {
@@ -3174,13 +3071,6 @@
advance();
return n.key;
}
- public int characteristics() {
- return Spliterator.DISTINCT | Spliterator.ORDERED |
- Spliterator.SORTED;
- }
- public final Comparator<? super K> getComparator() {
- return SubMap.this.comparator();
- }
}
final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
@@ -3190,390 +3080,19 @@
advance();
return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
- public int characteristics() {
- return Spliterator.DISTINCT;
- }
- }
- }
-
- // default Map method overrides
-
- public void forEach(BiConsumer<? super K, ? super V> action) {
- if (action == null) throw new NullPointerException();
- 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();
- 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;
- }
- }
- }
-
- /**
- * Helper method for EntrySet.removeIf.
- */
- boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
- if (function == null) throw new NullPointerException();
- boolean removed = false;
- 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;
- }
-
- /**
- * Helper method for Values.removeIf.
- */
- boolean removeValueIf(Predicate<? super V> function) {
- if (function == null) throw new NullPointerException();
- boolean removed = false;
- 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;
- }
- }
- return removed;
- }
-
- /**
- * Base class providing common structure for Spliterators.
- * (Although not all that much common functionality; as usual for
- * view classes, details annoyingly vary in key, value, and entry
- * subclasses in ways that are not worth abstracting out for
- * internal classes.)
- *
- * The basic split strategy is to recursively descend from top
- * level, row by row, descending to next row when either split
- * 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%. 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
- int est; // pseudo-size estimate
- CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
- 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 (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, int est) {
- super(comparator, row, origin, fence, est);
- }
-
- public KeySpliterator<K,V> trySplit() {
- Node<K,V> e; K ek;
- Comparator<? super K> cmp = comparator;
- K f = fence;
- if ((e = current) != null && (ek = e.key) != null) {
- 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.value != null &&
- (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
- (f == null || cpr(cmp, sk, f) < 0)) {
- current = n;
- Index<K,V> r = q.down;
- row = (s.right != null) ? s : s.down;
- est -= est >>> 2;
- return new KeySpliterator<K,V>(cmp, r, e, sk, est);
- }
- }
- }
- return null;
- }
-
- public void forEachRemaining(Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- current = null;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
- break;
- if ((v = e.value) != null && v != e)
- action.accept(k);
- }
- }
-
- public boolean tryAdvance(Consumer<? super K> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
- e = null;
- break;
- }
- if ((v = e.value) != null && v != e) {
- current = e.next;
- action.accept(k);
- return true;
- }
- }
- current = e;
- return false;
- }
-
- public int characteristics() {
- return Spliterator.DISTINCT | Spliterator.SORTED |
- Spliterator.ORDERED | Spliterator.CONCURRENT |
- Spliterator.NONNULL;
- }
-
- public final Comparator<? super K> getComparator() {
- return comparator;
- }
- }
- // factory method for KeySpliterator
- final KeySpliterator<K,V> keySpliterator() {
- 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);
- }
- }
-
- 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, int est) {
- super(comparator, row, origin, fence, est);
- }
-
- public ValueSpliterator<K,V> trySplit() {
- Node<K,V> e; K ek;
- Comparator<? super K> cmp = comparator;
- K f = fence;
- if ((e = current) != null && (ek = e.key) != null) {
- 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.value != null &&
- (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
- (f == null || cpr(cmp, sk, f) < 0)) {
- current = n;
- Index<K,V> r = q.down;
- row = (s.right != null) ? s : s.down;
- est -= est >>> 2;
- return new ValueSpliterator<K,V>(cmp, r, e, sk, est);
- }
- }
- }
- return null;
- }
-
- public void forEachRemaining(Consumer<? super V> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- current = null;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
- break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
- }
- }
- }
-
- public boolean tryAdvance(Consumer<? super V> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
- e = null;
- break;
- }
- if ((v = e.value) != null && v != e) {
- current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
- return true;
- }
- }
- current = e;
- return false;
- }
-
- public int characteristics() {
- return Spliterator.CONCURRENT | Spliterator.ORDERED |
- Spliterator.NONNULL;
- }
- }
-
- // Almost the same as keySpliterator()
- final ValueSpliterator<K,V> valueSpliterator() {
- 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);
- }
- }
-
- 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, int est) {
- super(comparator, row, origin, fence, est);
- }
-
- public EntrySpliterator<K,V> trySplit() {
- Node<K,V> e; K ek;
- Comparator<? super K> cmp = comparator;
- K f = fence;
- if ((e = current) != null && (ek = e.key) != null) {
- 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.value != null &&
- (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
- (f == null || cpr(cmp, sk, f) < 0)) {
- current = n;
- Index<K,V> r = q.down;
- row = (s.right != null) ? s : s.down;
- est -= est >>> 2;
- return new EntrySpliterator<K,V>(cmp, r, e, sk, est);
- }
- }
- }
- return null;
- }
-
- public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- current = null;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
- break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
- }
- }
- }
-
- public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
- if (action == null) throw new NullPointerException();
- Comparator<? super K> cmp = comparator;
- K f = fence;
- Node<K,V> e = current;
- for (; e != null; e = e.next) {
- K k; Object v;
- if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
- e = null;
- break;
- }
- if ((v = e.value) != null && v != e) {
- current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
- return true;
- }
- }
- current = e;
- return false;
- }
-
- public int characteristics() {
- return Spliterator.DISTINCT | Spliterator.SORTED |
- Spliterator.ORDERED | Spliterator.CONCURRENT |
- Spliterator.NONNULL;
- }
-
- public final Comparator<Map.Entry<K,V>> getComparator() {
- // Adapt or create a key-based comparator
- if (comparator != null) {
- return Map.Entry.comparingByKey(comparator);
- }
- else {
- return (Comparator<Map.Entry<K,V>> & Serializable) (e1, e2) -> {
- @SuppressWarnings("unchecked")
- Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
- return k1.compareTo(e2.getKey());
- };
- }
- }
- }
-
- // Almost the same as keySpliterator()
- final EntrySpliterator<K,V> entrySpliterator() {
- 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);
}
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
static {
try {
- HEAD = U.objectFieldOffset
- (ConcurrentSkipListMap.class.getDeclaredField("head"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ConcurrentSkipListMap.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index 1719822..13f1a43 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -6,21 +6,10 @@
package java.util.concurrent;
-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;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
// END android-note
/**
@@ -34,12 +23,12 @@
* cost for the {@code contains}, {@code add}, and {@code remove}
* operations and their variants. Insertion, removal, and access
* operations safely execute concurrently by multiple threads.
- *
- * <p>Iterators and spliterators are
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>Ascending ordered views and their iterators are faster than
- * descending ones.
+ * Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the set at some point at or since the
+ * creation of the iterator. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}, and may proceed concurrently with
+ * other operations. Ascending ordered views and their iterators are
+ * faster than descending ones.
*
* <p>Beware that, unlike in most collections, the {@code size}
* method is <em>not</em> a constant-time operation. Because of the
@@ -296,9 +285,8 @@
*
* @param c collection containing elements to be removed from this set
* @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="../Collection.html#optional-restrictions">optional</a>)
+ * @throws ClassCastException if the types of one or more elements in this
+ * set are incompatible with the specified collection
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
@@ -358,19 +346,20 @@
/* ---------------- SortedSet operations -------------- */
+
public Comparator<? super E> comparator() {
return m.comparator();
}
/**
- * @throws java.util.NoSuchElementException {@inheritDoc}
+ * @throws NoSuchElementException {@inheritDoc}
*/
public E first() {
return m.firstKey();
}
/**
- * @throws java.util.NoSuchElementException {@inheritDoc}
+ * @throws NoSuchElementException {@inheritDoc}
*/
public E last() {
return m.lastKey();
@@ -453,42 +442,20 @@
return new ConcurrentSkipListSet<E>(m.descendingMap());
}
- /**
- * Returns a {@link Spliterator} over the elements in this set.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
- * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
- * encounter order that is ascending order. Overriding implementations
- * should document the reporting of additional characteristic values.
- *
- * <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.
- *
- * @return a {@code Spliterator} over the elements in this set
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return (m instanceof ConcurrentSkipListMap)
- ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
- : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
- }
-
// Support for resetting map in clone
private void setMap(ConcurrentNavigableMap<E,Object> map) {
- U.putObjectVolatile(this, MAP, map);
+ UNSAFE.putObjectVolatile(this, mapOffset, map);
}
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long MAP;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long mapOffset;
static {
try {
- MAP = U.objectFieldOffset
- (ConcurrentSkipListSet.class.getDeclaredField("m"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ConcurrentSkipListSet.class;
+ mapOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("m"));
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
index c8e342e..798eaaf 100644
--- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
@@ -1,1542 +1,783 @@
/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group. Adapted and released, under explicit permission,
- * from JDK ArrayList.java which carries the following copyright:
+ * Copyright (C) 2010 The Android Open Source Project
*
- * Copyright 1997 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
+ * 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
*
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
+ * 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 java.util.concurrent;
-
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
-import java.util.Objects;
import java.util.RandomAccess;
-import java.util.Spliterator;
-import java.util.Spliterators;
import java.util.function.Consumer;
-import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
-import libcore.util.EmptyArray;
-// BEGIN android-note
-// removed link to collections framework docs from header
-// END android-note
+import libcore.util.EmptyArray;
+import libcore.util.Objects;
/**
- * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
- * operations ({@code add}, {@code set}, and so on) are implemented by
- * making a fresh copy of the underlying array.
+ * A thread-safe random-access list.
*
- * <p>This is ordinarily too costly, but may be <em>more</em> efficient
- * than alternatives when traversal operations vastly outnumber
- * mutations, and is useful when you cannot or don't want to
- * synchronize traversals, yet need to preclude interference among
- * concurrent threads. The "snapshot" style iterator method uses a
- * reference to the state of the array at the point that the iterator
- * was created. This array never changes during the lifetime of the
- * iterator, so interference is impossible and the iterator is
- * guaranteed not to throw {@code ConcurrentModificationException}.
- * The iterator will not reflect additions, removals, or changes to
- * the list since the iterator was created. Element-changing
- * operations on iterators themselves ({@code remove}, {@code set}, and
- * {@code add}) are not supported. These methods throw
- * {@code UnsupportedOperationException}.
+ * <p>Read operations (including {@link #get}) do not block and may overlap with
+ * update operations. Reads reflect the results of the most recently completed
+ * operations. Aggregate operations like {@link #addAll} and {@link #clear} are
+ * atomic; they never expose an intermediate state.
*
- * <p>All elements are permitted, including {@code null}.
+ * <p>Iterators of this list never throw {@link
+ * ConcurrentModificationException}. When an iterator is created, it keeps a
+ * copy of the list's contents. It is always safe to iterate this list, but
+ * iterations may not reflect the latest state of the list.
*
- * <p>Memory consistency effects: As with other concurrent
- * collections, actions in a thread prior to placing an object into a
- * {@code CopyOnWriteArrayList}
- * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
- * actions subsequent to the access or removal of that element from
- * the {@code CopyOnWriteArrayList} in another thread.
+ * <p>Iterators returned by this list and its sub lists cannot modify the
+ * underlying list. In particular, {@link Iterator#remove}, {@link
+ * ListIterator#add} and {@link ListIterator#set} all throw {@link
+ * UnsupportedOperationException}.
*
- * @since 1.5
- * @author Doug Lea
- * @param <E> the type of elements held in this list
+ * <p>This class offers extended API beyond the {@link List} interface. It
+ * includes additional overloads for indexed search ({@link #indexOf} and {@link
+ * #lastIndexOf}) and methods for conditional adds ({@link #addIfAbsent} and
+ * {@link #addAllAbsent}).
*/
-public class CopyOnWriteArrayList<E>
- implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
+public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
+
private static final long serialVersionUID = 8673264195747942595L;
/**
- * The lock protecting all mutators. (We have a mild preference
- * for builtin monitors over ReentrantLock when either will do.)
+ * Holds the latest snapshot of the list's data. This field is volatile so
+ * that data can be read without synchronization. As a consequence, all
+ * writes to this field must be atomic; it is an error to modify the
+ * contents of an array after it has been assigned to this field.
+ *
+ * Synchronization is required by all update operations. This defends
+ * against one update clobbering the result of another operation. For
+ * example, 100 threads simultaneously calling add() will grow the list's
+ * size by 100 when they have completed. No update operations are lost!
+ *
+ * Maintainers should be careful to read this field only once in
+ * non-blocking read methods. Write methods must be synchronized to avoid
+ * clobbering concurrent writes.
*/
- final transient Object lock = new Object();
-
- /** The array, accessed only via getArray/setArray. */
- private transient volatile Object[] array;
+ private transient volatile Object[] elements;
/**
- * Gets the array. Non-private so as to also be accessible
- * from CopyOnWriteArraySet class.
- */
- final Object[] getArray() {
- return array;
- }
-
- /**
- * Sets the array.
- */
- final void setArray(Object[] a) {
- array = a;
- }
-
- /**
- * Creates an empty list.
+ * Creates a new empty instance.
*/
public CopyOnWriteArrayList() {
- setArray(new Object[0]);
+ elements = EmptyArray.OBJECT;
}
/**
- * Creates a list containing the elements of the specified
- * collection, in the order they are returned by the collection's
- * iterator.
- *
- * @param c the collection of initially held elements
- * @throws NullPointerException if the specified collection is null
+ * Creates a new instance containing the elements of {@code collection}.
*/
- public CopyOnWriteArrayList(Collection<? extends E> c) {
- Object[] elements;
- if (c.getClass() == CopyOnWriteArrayList.class)
- elements = ((CopyOnWriteArrayList<?>)c).getArray();
- else {
- elements = c.toArray();
- // defend against c.toArray (incorrectly) not returning Object[]
- // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
- if (elements.getClass() != Object[].class)
- elements = Arrays.copyOf(elements, elements.length, Object[].class);
- }
- setArray(elements);
+ @SuppressWarnings("unchecked")
+ public CopyOnWriteArrayList(Collection<? extends E> collection) {
+ this((E[]) collection.toArray());
}
/**
- * Creates a list holding a copy of the given array.
- *
- * @param toCopyIn the array (a copy of this array is used as the
- * internal array)
- * @throws NullPointerException if the specified array is null
+ * Creates a new instance containing the elements of {@code array}.
*/
- public CopyOnWriteArrayList(E[] toCopyIn) {
- setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
+ public CopyOnWriteArrayList(E[] array) {
+ this.elements = Arrays.copyOf(array, array.length, Object[].class);
}
- /**
- * Returns the number of elements in this list.
- *
- * @return the number of elements in this list
- */
- public int size() {
- return getArray().length;
- }
-
- /**
- * Returns {@code true} if this list contains no elements.
- *
- * @return {@code true} if this list contains no elements
- */
- public boolean isEmpty() {
- return size() == 0;
- }
-
- /**
- * static version of indexOf, to allow repeated calls without
- * needing to re-acquire array each time.
- * @param o element to search for
- * @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 indexOf(Object o, Object[] elements,
- int index, int fence) {
- if (o == null) {
- for (int i = index; i < fence; i++)
- if (elements[i] == null)
- return i;
- } else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
- return i;
- }
- return -1;
- }
-
- /**
- * static version of lastIndexOf.
- * @param o element to search for
- * @param elements the array
- * @param index first index to search
- * @return index of element, or -1 if absent
- */
- private static int lastIndexOf(Object o, Object[] elements, int index) {
- if (o == null) {
- for (int i = index; i >= 0; i--)
- if (elements[i] == null)
- return i;
- } else {
- for (int i = index; i >= 0; i--)
- if (o.equals(elements[i]))
- return i;
- }
- return -1;
- }
-
- /**
- * Returns {@code true} if this list contains the specified element.
- * More formally, returns {@code true} if and only if this list contains
- * at least one element {@code e} such that {@code Objects.equals(o, e)}.
- *
- * @param o element whose presence in this list is to be tested
- * @return {@code true} if this list contains the specified element
- */
- public boolean contains(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length) >= 0;
- }
-
- /**
- * {@inheritDoc}
- */
- public int indexOf(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length);
- }
-
- /**
- * Returns the index of the first occurrence of the specified element in
- * this list, searching forwards from {@code index}, or returns -1 if
- * the element is not found.
- * More formally, returns the lowest index {@code i} such that
- * {@code i >= index && Objects.equals(get(i), e)},
- * or -1 if there is no such index.
- *
- * @param e element to search for
- * @param index index to start searching from
- * @return the index of the first occurrence of the element in
- * this list at position {@code index} or later in the list;
- * {@code -1} if the element is not found.
- * @throws IndexOutOfBoundsException if the specified index is negative
- */
- public int indexOf(E e, int index) {
- Object[] elements = getArray();
- return indexOf(e, elements, index, elements.length);
- }
-
- /**
- * {@inheritDoc}
- */
- public int lastIndexOf(Object o) {
- Object[] elements = getArray();
- return lastIndexOf(o, elements, elements.length - 1);
- }
-
- /**
- * Returns the index of the last occurrence of the specified element in
- * this list, searching backwards from {@code index}, or returns -1 if
- * the element is not found.
- * More formally, returns the highest index {@code i} such that
- * {@code i <= index && Objects.equals(get(i), e)},
- * or -1 if there is no such index.
- *
- * @param e element to search for
- * @param index index to start searching backwards from
- * @return the index of the last occurrence of the element at position
- * less than or equal to {@code index} in this list;
- * -1 if the element is not found.
- * @throws IndexOutOfBoundsException if the specified index is greater
- * than or equal to the current size of this list
- */
- public int lastIndexOf(E e, int index) {
- Object[] elements = getArray();
- return lastIndexOf(e, elements, index);
- }
-
- /**
- * Returns a shallow copy of this list. (The elements themselves
- * are not copied.)
- *
- * @return a clone of this list
- */
- public Object clone() {
+ @Override public Object clone() {
try {
- @SuppressWarnings("unchecked")
- CopyOnWriteArrayList<E> clone =
- (CopyOnWriteArrayList<E>) super.clone();
- clone.resetLock();
- return clone;
+ CopyOnWriteArrayList result = (CopyOnWriteArrayList) super.clone();
+ result.elements = result.elements.clone();
+ return result;
} catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new AssertionError(e);
}
}
- /**
- * Returns an array containing all of the elements in this list
- * in proper sequence (from first to last element).
- *
- * <p>The returned array will be "safe" in that no references to it are
- * maintained by this list. (In other words, this method must allocate
- * a new array). The caller is thus free to modify the returned array.
- *
- * <p>This method acts as bridge between array-based and collection-based
- * APIs.
- *
- * @return an array containing all the elements in this list
- */
- public Object[] toArray() {
- Object[] elements = getArray();
- return Arrays.copyOf(elements, elements.length);
+ public int size() {
+ return elements.length;
}
- /**
- * Returns an array containing all of the elements in this list in
- * proper sequence (from first to last element); the runtime type of
- * the returned array is that of the specified array. If the list fits
- * in the specified array, it is returned therein. Otherwise, a new
- * array is allocated with the runtime type of the specified array and
- * the size of this list.
- *
- * <p>If this list fits in the specified array with room to spare
- * (i.e., the array has more elements than this list), the element in
- * the array immediately following the end of the list is set to
- * {@code null}. (This is useful in determining the length of this
- * list <i>only</i> if the caller knows that this list does not contain
- * any null elements.)
- *
- * <p>Like the {@link #toArray()} method, this method acts as bridge between
- * array-based and collection-based APIs. Further, this method allows
- * precise control over the runtime type of the output array, and may,
- * under certain circumstances, be used to save allocation costs.
- *
- * <p>Suppose {@code x} is a list known to contain only strings.
- * The following code can be used to dump the list into a newly
- * allocated array of {@code String}:
- *
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
- *
- * Note that {@code toArray(new Object[0])} is identical in function to
- * {@code toArray()}.
- *
- * @param a the array into which the elements of the list are to
- * be stored, if it is big enough; otherwise, a new array of the
- * same runtime type is allocated for this purpose.
- * @return an array containing all the elements in this list
- * @throws ArrayStoreException if the runtime type of the specified array
- * is not a supertype of the runtime type of every element in
- * this list
- * @throws NullPointerException if the specified array is null
- */
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(T[] a) {
- Object[] elements = getArray();
- int len = elements.length;
- if (a.length < len)
- return (T[]) Arrays.copyOf(elements, len, a.getClass());
- else {
- System.arraycopy(elements, 0, a, 0, len);
- if (a.length > len)
- a[len] = null;
- return a;
- }
- }
-
- // Positional Access Operations
-
@SuppressWarnings("unchecked")
- private E get(Object[] a, int index) {
- return (E) a[index];
- }
-
- static String outOfBounds(int index, int size) {
- return "Index: " + index + ", Size: " + size;
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws IndexOutOfBoundsException {@inheritDoc}
- */
public E get(int index) {
- return get(getArray(), index);
+ return (E) elements[index];
}
- /**
- * Replaces the element at the specified position in this list with the
- * specified element.
- *
- * @throws IndexOutOfBoundsException {@inheritDoc}
- */
- public E set(int index, E element) {
- synchronized (lock) {
- Object[] elements = getArray();
- E oldValue = get(elements, index);
-
- if (oldValue != element) {
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len);
- newElements[index] = element;
- setArray(newElements);
- } else {
- // Not quite a no-op; ensures volatile write semantics
- setArray(elements);
- }
- return oldValue;
- }
+ public boolean contains(Object o) {
+ return indexOf(o) != -1;
}
- /**
- * Appends the specified element to the end of this list.
- *
- * @param e element to be appended to this list
- * @return {@code true} (as specified by {@link Collection#add})
- */
- public boolean add(E e) {
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len + 1);
- newElements[len] = e;
- setArray(newElements);
- return true;
- }
+ public boolean containsAll(Collection<?> collection) {
+ Object[] snapshot = elements;
+ return containsAll(collection, snapshot, 0, snapshot.length);
}
- /**
- * Inserts the specified element at the specified position in this
- * list. Shifts the element currently at that position (if any) and
- * any subsequent elements to the right (adds one to their indices).
- *
- * @throws IndexOutOfBoundsException {@inheritDoc}
- */
- public void add(int index, E element) {
- synchronized (lock) {
- 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(elements, len + 1);
- else {
- newElements = new Object[len + 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index, newElements, index + 1,
- numMoved);
- }
- newElements[index] = element;
- setArray(newElements);
- }
- }
-
- /**
- * Removes the element at the specified position in this list.
- * Shifts any subsequent elements to the left (subtracts one from their
- * indices). Returns the element that was removed from the list.
- *
- * @throws IndexOutOfBoundsException {@inheritDoc}
- */
- public E remove(int index) {
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- E oldValue = get(elements, index);
- int numMoved = len - index - 1;
- if (numMoved == 0)
- setArray(Arrays.copyOf(elements, len - 1));
- else {
- Object[] newElements = new Object[len - 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index + 1, newElements, index,
- numMoved);
- setArray(newElements);
- }
- return oldValue;
- }
- }
-
- /**
- * Removes the first occurrence of the specified element from this list,
- * if it is present. If this list does not contain the element, it is
- * unchanged. More formally, removes the element with the lowest index
- * {@code i} such that {@code Objects.equals(o, get(i))}
- * (if such an element exists). Returns {@code true} if this list
- * contained the specified element (or equivalently, if this list
- * changed as a result of the call).
- *
- * @param o element to be removed from this list, if present
- * @return {@code true} if this list contained the specified element
- */
- public boolean remove(Object o) {
- Object[] snapshot = getArray();
- int index = indexOf(o, snapshot, 0, snapshot.length);
- return (index < 0) ? false : remove(o, snapshot, index);
- }
-
- /**
- * A version of remove(Object) using the strong hint that given
- * recent snapshot contains o at the given index.
- */
- private boolean remove(Object o, Object[] snapshot, int index) {
- synchronized (lock) {
- Object[] current = getArray();
- int len = current.length;
- if (snapshot != current) findIndex: {
- int prefix = Math.min(index, len);
- for (int i = 0; i < prefix; i++) {
- if (current[i] != snapshot[i]
- && Objects.equals(o, current[i])) {
- index = i;
- break findIndex;
- }
- }
- if (index >= len)
- return false;
- if (current[index] == o)
- break findIndex;
- index = indexOf(o, current, index, len);
- if (index < 0)
- return false;
- }
- Object[] newElements = new Object[len - 1];
- System.arraycopy(current, 0, newElements, 0, index);
- System.arraycopy(current, index + 1,
- newElements, index,
- len - index - 1);
- setArray(newElements);
- return true;
- }
- }
-
- /**
- * Removes from this list all of the elements whose index is between
- * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
- * Shifts any succeeding elements to the left (reduces their index).
- * This call shortens the list by {@code (toIndex - fromIndex)} elements.
- * (If {@code toIndex==fromIndex}, this operation has no effect.)
- *
- * @param fromIndex index of first element to be removed
- * @param toIndex index after last element to be removed
- * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range
- * ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
- */
- void removeRange(int fromIndex, int toIndex) {
- synchronized (lock) {
- 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(elements, newlen));
- else {
- Object[] newElements = new Object[newlen];
- System.arraycopy(elements, 0, newElements, 0, fromIndex);
- System.arraycopy(elements, toIndex, newElements,
- fromIndex, numMoved);
- setArray(newElements);
- }
- }
- }
-
- /**
- * Appends the element, if not present.
- *
- * @param e element to be added to this list, if absent
- * @return {@code true} if the element was added
- */
- public boolean addIfAbsent(E e) {
- Object[] snapshot = getArray();
- return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
- addIfAbsent(e, snapshot);
- }
-
- /**
- * A version of addIfAbsent using the strong hint that given
- * recent snapshot does not contain e.
- */
- private boolean addIfAbsent(E e, Object[] snapshot) {
- synchronized (lock) {
- Object[] current = getArray();
- int len = current.length;
- if (snapshot != current) {
- // Optimize for lost race to another addXXX operation
- int common = Math.min(snapshot.length, len);
- for (int i = 0; i < common; i++)
- if (current[i] != snapshot[i]
- && Objects.equals(e, current[i]))
- return false;
- if (indexOf(e, current, common, len) >= 0)
- return false;
- }
- Object[] newElements = Arrays.copyOf(current, len + 1);
- newElements[len] = e;
- setArray(newElements);
- return true;
- }
- }
-
- /**
- * Returns {@code true} if this list contains all of the elements of the
- * specified collection.
- *
- * @param c collection to be checked for containment in this list
- * @return {@code true} if this list contains all of the elements of the
- * specified collection
- * @throws NullPointerException if the specified collection is null
- * @see #contains(Object)
- */
- public boolean containsAll(Collection<?> c) {
- Object[] elements = getArray();
- int len = elements.length;
- for (Object e : c) {
- if (indexOf(e, elements, 0, len) < 0)
+ static boolean containsAll(Collection<?> collection, Object[] snapshot, int from, int to) {
+ for (Object o : collection) {
+ if (indexOf(o, snapshot, from, to) == -1) {
return false;
+ }
}
return true;
}
/**
- * Removes from this list all of its elements that are contained in
- * the specified collection. This is a particularly expensive operation
- * in this class because of the need for an internal temporary array.
+ * Searches this list for {@code object} and returns the index of the first
+ * occurrence that is at or after {@code from}.
*
- * @param c collection containing elements to be removed from this list
- * @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}/../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}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
- * or if the specified collection is null
- * @see #remove(Object)
+ * @return the index or -1 if the object was not found.
*/
- public boolean removeAll(Collection<?> c) {
- 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;
- }
+ public int indexOf(E object, int from) {
+ Object[] snapshot = elements;
+ return indexOf(object, snapshot, from, snapshot.length);
+ }
+
+ public int indexOf(Object object) {
+ Object[] snapshot = elements;
+ return indexOf(object, snapshot, 0, snapshot.length);
}
/**
- * Retains only the elements in this list that are contained in the
- * specified collection. In other words, removes from this list all of
- * its elements that are not contained in the specified collection.
+ * Searches this list for {@code object} and returns the index of the last
+ * occurrence that is before {@code to}.
*
- * @param c collection containing elements to be retained in this list
- * @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}/../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}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
- * or if the specified collection is null
- * @see #remove(Object)
+ * @return the index or -1 if the object was not found.
*/
- public boolean retainAll(Collection<?> c) {
- 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;
- }
+ public int lastIndexOf(E object, int to) {
+ Object[] snapshot = elements;
+ return lastIndexOf(object, snapshot, 0, to);
+ }
+
+ public int lastIndexOf(Object object) {
+ Object[] snapshot = elements;
+ return lastIndexOf(object, snapshot, 0, snapshot.length);
+ }
+
+ public boolean isEmpty() {
+ return elements.length == 0;
}
/**
- * Appends all of the elements in the specified collection that
- * are not already contained in this list, to the end of
- * this list, in the order that they are returned by the
- * specified collection's iterator.
+ * Returns an {@link Iterator} that iterates over the elements of this list
+ * as they were at the time of this method call. Changes to the list made
+ * after this method call will not be reflected by the iterator, nor will
+ * they trigger a {@link ConcurrentModificationException}.
*
- * @param c collection containing elements to be added to this list
- * @return the number of elements added
- * @throws NullPointerException if the specified collection is null
- * @see #addIfAbsent(Object)
- */
- public int addAllAbsent(Collection<? extends E> c) {
- Object[] cs = c.toArray();
- if (cs.length == 0)
- return 0;
- synchronized (lock) {
- 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 (indexOf(e, elements, 0, len) < 0 &&
- indexOf(e, cs, 0, added) < 0)
- cs[added++] = e;
- }
- if (added > 0) {
- Object[] newElements = Arrays.copyOf(elements, len + added);
- System.arraycopy(cs, 0, newElements, len, added);
- setArray(newElements);
- }
- return added;
- }
- }
-
- /**
- * Removes all of the elements from this list.
- * The list will be empty after this call returns.
- */
- public void clear() {
- synchronized (lock) {
- setArray(new Object[0]);
- }
- }
-
- /**
- * Appends all of the elements in the specified collection to the end
- * of this list, in the order that they are returned by the specified
- * collection's iterator.
- *
- * @param c collection containing elements to be added to this list
- * @return {@code true} if this list changed as a result of the call
- * @throws NullPointerException if the specified collection is null
- * @see #add(Object)
- */
- public boolean addAll(Collection<? extends E> c) {
- Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
- ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
- if (cs.length == 0)
- return false;
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (len == 0 && cs.getClass() == Object[].class)
- setArray(cs);
- else {
- Object[] newElements = Arrays.copyOf(elements, len + cs.length);
- System.arraycopy(cs, 0, newElements, len, cs.length);
- setArray(newElements);
- }
- return true;
- }
- }
-
- /**
- * Inserts all of the elements in the specified collection into this
- * list, starting at the specified position. Shifts the element
- * currently at that position (if any) and any subsequent elements to
- * the right (increases their indices). The new elements will appear
- * in this list in the order that they are returned by the
- * specified collection's iterator.
- *
- * @param index index at which to insert the first element
- * from the specified collection
- * @param c collection containing elements to be added to this list
- * @return {@code true} if this list changed as a result of the call
- * @throws IndexOutOfBoundsException {@inheritDoc}
- * @throws NullPointerException if the specified collection is null
- * @see #add(int,Object)
- */
- public boolean addAll(int index, Collection<? extends E> c) {
- Object[] cs = c.toArray();
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (index > len || index < 0)
- throw new IndexOutOfBoundsException(outOfBounds(index, len));
- if (cs.length == 0)
- return false;
- int numMoved = len - index;
- Object[] newElements;
- if (numMoved == 0)
- newElements = Arrays.copyOf(elements, len + cs.length);
- else {
- newElements = new Object[len + cs.length];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index,
- newElements, index + cs.length,
- numMoved);
- }
- System.arraycopy(cs, 0, newElements, index, cs.length);
- setArray(newElements);
- return true;
- }
- }
-
- public void forEach(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- for (Object x : getArray()) {
- @SuppressWarnings("unchecked") E e = (E) x;
- action.accept(e);
- }
- }
-
- public boolean removeIf(Predicate<? super E> filter) {
- if (filter == null) throw new NullPointerException();
- synchronized (lock) {
- 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;
- }
- }
- return false; // zero matches => zero copies
- }
- }
-
- public void replaceAll(UnaryOperator<E> operator) {
- if (operator == null) throw new NullPointerException();
- synchronized (lock) {
- 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);
- }
- }
-
- public void sort(Comparator<? super E> c) {
- synchronized (lock) {
- Object[] elements = getArray();
- Object[] newElements = Arrays.copyOf(elements, elements.length);
- @SuppressWarnings("unchecked") E[] es = (E[])newElements;
- Arrays.sort(es, c);
- setArray(newElements);
- }
- }
-
- /**
- * Saves this list to a stream (that is, serializes it).
- *
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
- * @serialData The length of the array backing the list is emitted
- * (int), followed by all of its elements (each an Object)
- * in the proper order.
- */
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
-
- s.defaultWriteObject();
-
- Object[] elements = getArray();
- // Write out array length
- s.writeInt(elements.length);
-
- // Write out all elements in the proper order.
- for (Object element : elements)
- s.writeObject(element);
- }
-
- /**
- * Reconstitutes this list from a stream (that is, deserializes it).
- * @param s the stream
- * @throws ClassNotFoundException if the class of a serialized object
- * could not be found
- * @throws java.io.IOException if an I/O error occurs
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
-
- s.defaultReadObject();
-
- // bind to new lock
- resetLock();
-
- // Read in array length and allocate array
- int len = s.readInt();
- Object[] elements = new Object[len];
-
- // Read in all elements in the proper order.
- for (int i = 0; i < len; i++)
- elements[i] = s.readObject();
- setArray(elements);
- }
-
- /**
- * Returns a string representation of this list. The string
- * representation consists of the string representations of the list's
- * elements in the order they are returned by its iterator, enclosed in
- * square brackets ({@code "[]"}). Adjacent elements are separated by
- * the characters {@code ", "} (comma and space). Elements are
- * converted to strings as by {@link String#valueOf(Object)}.
- *
- * @return a string representation of this list
- */
- public String toString() {
- return Arrays.toString(getArray());
- }
-
- /**
- * Compares the specified object with this list for equality.
- * Returns {@code true} if the specified object is the same object
- * as this object, or if it is also a {@link List} and the sequence
- * of elements returned by an {@linkplain List#iterator() iterator}
- * over the specified list is the same as the sequence returned by
- * an iterator over this list. The two sequences are considered to
- * be the same if they have the same length and corresponding
- * elements at the same position in the sequence are <em>equal</em>.
- * Two elements {@code e1} and {@code e2} are considered
- * <em>equal</em> if {@code Objects.equals(e1, e2)}.
- *
- * @param o the object to be compared for equality with this list
- * @return {@code true} if the specified object is equal to this list
- */
- public boolean equals(Object o) {
- if (o == this)
- return true;
- if (!(o instanceof List))
- return false;
-
- List<?> list = (List<?>)o;
- Iterator<?> it = list.iterator();
- Object[] elements = getArray();
- for (int i = 0, len = elements.length; i < len; i++)
- if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
- return false;
- if (it.hasNext())
- return false;
- return true;
- }
-
- /**
- * Returns the hash code value for this list.
- *
- * <p>This implementation uses the definition in {@link List#hashCode}.
- *
- * @return the hash code value for this list
- */
- public int hashCode() {
- int hashCode = 1;
- for (Object x : getArray())
- hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
- return hashCode;
- }
-
- /**
- * Returns an iterator over the elements in this list in proper sequence.
- *
- * <p>The returned iterator provides a snapshot of the state of the list
- * when the iterator was constructed. No synchronization is needed while
- * traversing the iterator. The iterator does <em>NOT</em> support the
- * {@code remove} method.
- *
- * @return an iterator over the elements in this list in proper sequence
+ * <p>The returned iterator does not support {@link Iterator#remove()}.
*/
public Iterator<E> iterator() {
- return new COWIterator<E>(getArray(), 0);
+ Object[] snapshot = elements;
+ return new CowIterator<E>(snapshot, 0, snapshot.length);
}
/**
- * {@inheritDoc}
+ * Returns a {@link ListIterator} that iterates over the elements of this
+ * list as they were at the time of this method call. Changes to the list
+ * made after this method call will not be reflected by the iterator, nor
+ * will they trigger a {@link ConcurrentModificationException}.
*
- * <p>The returned iterator provides a snapshot of the state of the list
- * when the iterator was constructed. No synchronization is needed while
- * traversing the iterator. The iterator does <em>NOT</em> support the
- * {@code remove}, {@code set} or {@code add} methods.
- */
- public ListIterator<E> listIterator() {
- return new COWIterator<E>(getArray(), 0);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned iterator provides a snapshot of the state of the list
- * when the iterator was constructed. No synchronization is needed while
- * traversing the iterator. The iterator does <em>NOT</em> support the
- * {@code remove}, {@code set} or {@code add} methods.
- *
- * @throws IndexOutOfBoundsException {@inheritDoc}
+ * <p>The returned iterator does not support {@link ListIterator#add},
+ * {@link ListIterator#set} or {@link Iterator#remove()},
*/
public ListIterator<E> listIterator(int index) {
- Object[] elements = getArray();
- int len = elements.length;
- if (index < 0 || index > len)
- throw new IndexOutOfBoundsException(outOfBounds(index, len));
-
- return new COWIterator<E>(elements, index);
+ Object[] snapshot = elements;
+ if (index < 0 || index > snapshot.length) {
+ throw new IndexOutOfBoundsException("index=" + index + ", length=" + snapshot.length);
+ }
+ CowIterator<E> result = new CowIterator<E>(snapshot, 0, snapshot.length);
+ result.index = index;
+ return result;
}
/**
- * Returns a {@link Spliterator} over the elements in this list.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
- * {@link Spliterator#ORDERED}, {@link Spliterator#SIZED}, and
- * {@link Spliterator#SUBSIZED}.
- *
- * <p>The spliterator provides a snapshot of the state of the list
- * when the spliterator was constructed. No synchronization is needed while
- * operating on the spliterator.
- *
- * @return a {@code Spliterator} over the elements in this list
- * @since 1.8
+ * Equivalent to {@code listIterator(0)}.
*/
- public Spliterator<E> spliterator() {
- return Spliterators.spliterator
- (getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
+ public ListIterator<E> listIterator() {
+ Object[] snapshot = elements;
+ return new CowIterator<E>(snapshot, 0, snapshot.length);
}
- static final class COWIterator<E> implements ListIterator<E> {
- /** Snapshot of the array */
- private final Object[] snapshot;
- /** Index of element to be returned by subsequent call to next. */
- private int cursor;
-
- COWIterator(Object[] elements, int initialCursor) {
- cursor = initialCursor;
- snapshot = elements;
+ public List<E> subList(int from, int to) {
+ Object[] snapshot = elements;
+ if (from < 0 || from > to || to > snapshot.length) {
+ throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
+ ", list size=" + snapshot.length);
}
+ return new CowSubList(snapshot, from, to);
+ }
- public boolean hasNext() {
- return cursor < snapshot.length;
+ public Object[] toArray() {
+ return elements.clone();
+ }
+
+ @SuppressWarnings({"unchecked","SuspiciousSystemArraycopy"})
+ public <T> T[] toArray(T[] contents) {
+ Object[] snapshot = elements;
+ if (snapshot.length > contents.length) {
+ return (T[]) Arrays.copyOf(snapshot, snapshot.length, contents.getClass());
}
-
- public boolean hasPrevious() {
- return cursor > 0;
+ System.arraycopy(snapshot, 0, contents, 0, snapshot.length);
+ if (snapshot.length < contents.length) {
+ contents[snapshot.length] = null;
}
+ return contents;
+ }
- @SuppressWarnings("unchecked")
- public E next() {
- if (! hasNext())
- throw new NoSuchElementException();
- return (E) snapshot[cursor++];
- }
-
- @SuppressWarnings("unchecked")
- public E previous() {
- if (! hasPrevious())
- throw new NoSuchElementException();
- return (E) snapshot[--cursor];
- }
-
- public int nextIndex() {
- return cursor;
- }
-
- public int previousIndex() {
- return cursor-1;
- }
-
- /**
- * Not supported. Always throws UnsupportedOperationException.
- * @throws UnsupportedOperationException always; {@code remove}
- * is not supported by this iterator.
- */
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Not supported. Always throws UnsupportedOperationException.
- * @throws UnsupportedOperationException always; {@code set}
- * is not supported by this iterator.
- */
- public void set(E e) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Not supported. Always throws UnsupportedOperationException.
- * @throws UnsupportedOperationException always; {@code add}
- * is not supported by this iterator.
- */
- public void add(E e) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public void forEachRemaining(Consumer<? super E> action) {
- Objects.requireNonNull(action);
- final int size = snapshot.length;
- for (int i = cursor; i < size; i++) {
- action.accept((E) snapshot[i]);
+ @Override public boolean equals(Object other) {
+ if (other instanceof CopyOnWriteArrayList) {
+ return this == other
+ || Arrays.equals(elements, ((CopyOnWriteArrayList<?>) other).elements);
+ } else if (other instanceof List) {
+ Object[] snapshot = elements;
+ Iterator<?> i = ((List<?>) other).iterator();
+ for (Object o : snapshot) {
+ if (!i.hasNext() || !Objects.equal(o, i.next())) {
+ return false;
+ }
}
- cursor = size;
+ return !i.hasNext();
+ } else {
+ return false;
}
}
+ @Override public int hashCode() {
+ return Arrays.hashCode(elements);
+ }
+
+ @Override public String toString() {
+ return Arrays.toString(elements);
+ }
+
+ public synchronized boolean add(E e) {
+ Object[] newElements = new Object[elements.length + 1];
+ System.arraycopy(elements, 0, newElements, 0, elements.length);
+ newElements[elements.length] = e;
+ elements = newElements;
+ return true;
+ }
+
+ public synchronized void add(int index, E e) {
+ Object[] newElements = new Object[elements.length + 1];
+ System.arraycopy(elements, 0, newElements, 0, index);
+ newElements[index] = e;
+ System.arraycopy(elements, index, newElements, index + 1, elements.length - index);
+ elements = newElements;
+ }
+
+ public synchronized boolean addAll(Collection<? extends E> collection) {
+ return addAll(elements.length, collection);
+ }
+
+ public synchronized boolean addAll(int index, Collection<? extends E> collection) {
+ Object[] toAdd = collection.toArray();
+ Object[] newElements = new Object[elements.length + toAdd.length];
+ System.arraycopy(elements, 0, newElements, 0, index);
+ System.arraycopy(toAdd, 0, newElements, index, toAdd.length);
+ System.arraycopy(elements, index,
+ newElements, index + toAdd.length, elements.length - index);
+ elements = newElements;
+ return toAdd.length > 0;
+ }
+
/**
- * Returns a view of the portion of this list between
- * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
- * The returned list is backed by this list, so changes in the
- * returned list are reflected in this list.
+ * Adds the elements of {@code collection} that are not already present in
+ * this list. If {@code collection} includes a repeated value, at most one
+ * occurrence of that value will be added to this list. Elements are added
+ * at the end of this list.
*
- * <p>The semantics of the list returned by this method become
- * undefined if the backing list (i.e., this list) is modified in
- * any way other than via the returned list.
- *
- * @param fromIndex low endpoint (inclusive) of the subList
- * @param toIndex high endpoint (exclusive) of the subList
- * @return a view of the specified range within this list
- * @throws IndexOutOfBoundsException {@inheritDoc}
+ * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
+ * API is more appropriate for set operations.
*/
- public List<E> subList(int fromIndex, int toIndex) {
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
- throw new IndexOutOfBoundsException();
- return new COWSubList<E>(this, fromIndex, toIndex);
+ public synchronized int addAllAbsent(Collection<? extends E> collection) {
+ Object[] toAdd = collection.toArray();
+ Object[] newElements = new Object[elements.length + toAdd.length];
+ System.arraycopy(elements, 0, newElements, 0, elements.length);
+ int addedCount = 0;
+ for (Object o : toAdd) {
+ if (indexOf(o, newElements, 0, elements.length + addedCount) == -1) {
+ newElements[elements.length + addedCount++] = o;
+ }
}
+ if (addedCount < toAdd.length) {
+ newElements = Arrays.copyOfRange(
+ newElements, 0, elements.length + addedCount); // trim to size
+ }
+ elements = newElements;
+ return addedCount;
}
/**
- * 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.
+ * Adds {@code object} to the end of this list if it is not already present.
+ *
+ * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
+ * API is more appropriate for set operations.
*/
- 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;
+ public synchronized boolean addIfAbsent(E object) {
+ if (contains(object)) {
+ return false;
+ }
+ add(object);
+ return true;
+ }
- // 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;
+ @Override public synchronized void clear() {
+ elements = EmptyArray.OBJECT;
+ }
+
+ public synchronized E remove(int index) {
+ @SuppressWarnings("unchecked")
+ E removed = (E) elements[index];
+ removeRange(index, index + 1);
+ return removed;
+ }
+
+ public synchronized boolean remove(Object o) {
+ int index = indexOf(o);
+ if (index == -1) {
+ return false;
+ }
+ remove(index);
+ return true;
+ }
+
+ public synchronized boolean removeAll(Collection<?> collection) {
+ return removeOrRetain(collection, false, 0, elements.length) != 0;
+ }
+
+ public synchronized boolean retainAll(Collection<?> collection) {
+ return removeOrRetain(collection, true, 0, elements.length) != 0;
+ }
+
+ /**
+ * Removes or retains the elements in {@code collection}. Returns the number
+ * of elements removed.
+ */
+ private int removeOrRetain(Collection<?> collection, boolean retain, int from, int to) {
+ for (int i = from; i < to; i++) {
+ if (collection.contains(elements[i]) == retain) {
+ continue;
+ }
+
+ /*
+ * We've encountered an element that must be removed! Create a new
+ * array and copy in the surviving elements one by one.
+ */
+ Object[] newElements = new Object[elements.length - 1];
+ System.arraycopy(elements, 0, newElements, 0, i);
+ int newSize = i;
+ for (int j = i + 1; j < to; j++) {
+ if (collection.contains(elements[j]) == retain) {
+ newElements[newSize++] = elements[j];
+ }
+ }
+
+ /*
+ * Copy the elements after 'to'. This is only useful for sub lists,
+ * where 'to' will be less than elements.length.
+ */
+ System.arraycopy(elements, to, newElements, newSize, elements.length - to);
+ newSize += (elements.length - to);
+
+ if (newSize < newElements.length) {
+ newElements = Arrays.copyOfRange(newElements, 0, newSize); // trim to size
+ }
+ int removed = elements.length - newElements.length;
+ elements = newElements;
+ return removed;
}
- // only call this holding l's lock
- private void checkForComodification() {
- // assert Thread.holdsLock(l.lock);
- if (l.getArray() != expectedArray)
- throw new ConcurrentModificationException();
+ // we made it all the way through the loop without making any changes
+ return 0;
+ }
+
+ public synchronized E set(int index, E e) {
+ Object[] newElements = elements.clone();
+ @SuppressWarnings("unchecked")
+ E result = (E) newElements[index];
+ newElements[index] = e;
+ elements = newElements;
+ return result;
+ }
+
+ private void removeRange(int from, int to) {
+ Object[] newElements = new Object[elements.length - (to - from)];
+ System.arraycopy(elements, 0, newElements, 0, from);
+ System.arraycopy(elements, to, newElements, from, elements.length - to);
+ elements = newElements;
+ }
+
+ static int lastIndexOf(Object o, Object[] data, int from, int to) {
+ if (o == null) {
+ for (int i = to - 1; i >= from; i--) {
+ if (data[i] == null) {
+ return i;
+ }
+ }
+ } else {
+ for (int i = to - 1; i >= from; i--) {
+ if (o.equals(data[i])) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ static int indexOf(Object o, Object[] data, int from, int to) {
+ if (o == null) {
+ for (int i = from; i < to; i++) {
+ if (data[i] == null) {
+ return i;
+ }
+ }
+ } else {
+ for (int i = from; i < to; i++) {
+ if (o.equals(data[i])) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ final Object[] getArray() {
+ // CopyOnWriteArraySet needs this.
+ return elements;
+ }
+
+ /**
+ * The sub list is thread safe and supports non-blocking reads. Doing so is
+ * more difficult than in the full list, because each read needs to examine
+ * four fields worth of state:
+ * - the elements array of the full list
+ * - two integers for the bounds of this sub list
+ * - the expected elements array (to detect concurrent modification)
+ *
+ * This is accomplished by aggregating the sub list's three fields into a
+ * single snapshot object representing the current slice. This permits reads
+ * to be internally consistent without synchronization. This takes advantage
+ * of Java's concurrency semantics for final fields.
+ */
+ class CowSubList extends AbstractList<E> {
+
+ /*
+ * An immutable snapshot of a sub list's state. By gathering all three
+ * of the sub list's fields in an immutable object,
+ */
+ private volatile Slice slice;
+
+ public CowSubList(Object[] expectedElements, int from, int to) {
+ this.slice = new Slice(expectedElements, from, to);
}
- // only call this holding l's lock
- private void rangeCheck(int index) {
- // assert Thread.holdsLock(l.lock);
- if (index < 0 || index >= size)
- throw new IndexOutOfBoundsException(outOfBounds(index, size));
+ @Override public int size() {
+ Slice slice = this.slice;
+ return slice.to - slice.from;
}
- public E set(int index, E element) {
- synchronized (l.lock) {
- rangeCheck(index);
- checkForComodification();
- E x = l.set(index+offset, element);
- expectedArray = l.getArray();
- return x;
+ @Override public boolean isEmpty() {
+ Slice slice = this.slice;
+ return slice.from == slice.to;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public E get(int index) {
+ Slice slice = this.slice;
+ Object[] snapshot = elements;
+ slice.checkElementIndex(index);
+ slice.checkConcurrentModification(snapshot);
+ return (E) snapshot[index + slice.from];
+ }
+
+ @Override public Iterator<E> iterator() {
+ return listIterator(0);
+ }
+
+ @Override public ListIterator<E> listIterator() {
+ return listIterator(0);
+ }
+
+ @Override public ListIterator<E> listIterator(int index) {
+ Slice slice = this.slice;
+ Object[] snapshot = elements;
+ slice.checkPositionIndex(index);
+ slice.checkConcurrentModification(snapshot);
+ CowIterator<E> result = new CowIterator<E>(snapshot, slice.from, slice.to);
+ result.index = slice.from + index;
+ return result;
+ }
+
+ @Override public int indexOf(Object object) {
+ Slice slice = this.slice;
+ Object[] snapshot = elements;
+ slice.checkConcurrentModification(snapshot);
+ int result = CopyOnWriteArrayList.indexOf(object, snapshot, slice.from, slice.to);
+ return (result != -1) ? (result - slice.from) : -1;
+ }
+
+ @Override public int lastIndexOf(Object object) {
+ Slice slice = this.slice;
+ Object[] snapshot = elements;
+ slice.checkConcurrentModification(snapshot);
+ int result = CopyOnWriteArrayList.lastIndexOf(object, snapshot, slice.from, slice.to);
+ return (result != -1) ? (result - slice.from) : -1;
+ }
+
+ @Override public boolean contains(Object object) {
+ return indexOf(object) != -1;
+ }
+
+ @Override public boolean containsAll(Collection<?> collection) {
+ Slice slice = this.slice;
+ Object[] snapshot = elements;
+ slice.checkConcurrentModification(snapshot);
+ return CopyOnWriteArrayList.containsAll(collection, snapshot, slice.from, slice.to);
+ }
+
+ @Override public List<E> subList(int from, int to) {
+ Slice slice = this.slice;
+ if (from < 0 || from > to || to > size()) {
+ throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
+ ", list size=" + size());
+ }
+ return new CowSubList(slice.expectedElements, slice.from + from, slice.from + to);
+ }
+
+ @Override public E remove(int index) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkElementIndex(index);
+ slice.checkConcurrentModification(elements);
+ E removed = CopyOnWriteArrayList.this.remove(slice.from + index);
+ slice = new Slice(elements, slice.from, slice.to - 1);
+ return removed;
}
}
- public E get(int index) {
- synchronized (l.lock) {
- rangeCheck(index);
- checkForComodification();
- return l.get(index+offset);
+ @Override public void clear() {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkConcurrentModification(elements);
+ CopyOnWriteArrayList.this.removeRange(slice.from, slice.to);
+ slice = new Slice(elements, slice.from, slice.from);
}
}
- public int size() {
- synchronized (l.lock) {
- checkForComodification();
- return size;
+ @Override public void add(int index, E object) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkPositionIndex(index);
+ slice.checkConcurrentModification(elements);
+ CopyOnWriteArrayList.this.add(index + slice.from, object);
+ slice = new Slice(elements, slice.from, slice.to + 1);
}
}
- public void add(int index, E element) {
- synchronized (l.lock) {
- checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- l.add(index+offset, element);
- expectedArray = l.getArray();
- size++;
+ @Override public boolean add(E object) {
+ synchronized (CopyOnWriteArrayList.this) {
+ add(slice.to - slice.from, object);
+ return true;
}
}
- public void clear() {
- synchronized (l.lock) {
- checkForComodification();
- l.removeRange(offset, offset+size);
- expectedArray = l.getArray();
- size = 0;
- }
- }
-
- public E remove(int index) {
- synchronized (l.lock) {
- rangeCheck(index);
- checkForComodification();
- E result = l.remove(index+offset);
- expectedArray = l.getArray();
- size--;
+ @Override public boolean addAll(int index, Collection<? extends E> collection) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkPositionIndex(index);
+ slice.checkConcurrentModification(elements);
+ int oldSize = elements.length;
+ boolean result = CopyOnWriteArrayList.this.addAll(index + slice.from, collection);
+ slice = new Slice(elements, slice.from, slice.to + (elements.length - oldSize));
return result;
}
}
- public boolean remove(Object o) {
- int index = indexOf(o);
- if (index == -1)
- return false;
- remove(index);
- return true;
- }
-
- public Iterator<E> iterator() {
- synchronized (l.lock) {
- checkForComodification();
- return new COWSubListIterator<E>(l, 0, offset, size);
+ @Override public boolean addAll(Collection<? extends E> collection) {
+ synchronized (CopyOnWriteArrayList.this) {
+ return addAll(size(), collection);
}
}
- public ListIterator<E> listIterator(int index) {
- synchronized (l.lock) {
- checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- return new COWSubListIterator<E>(l, index, offset, size);
+ @Override public E set(int index, E object) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkElementIndex(index);
+ slice.checkConcurrentModification(elements);
+ E result = CopyOnWriteArrayList.this.set(index + slice.from, object);
+ slice = new Slice(elements, slice.from, slice.to);
+ return result;
}
}
- public List<E> subList(int fromIndex, int toIndex) {
- synchronized (l.lock) {
- checkForComodification();
- if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
- throw new IndexOutOfBoundsException();
- return new COWSubList<E>(l, fromIndex + offset,
- toIndex + offset);
- }
- }
-
- public void forEach(Consumer<? super E> action) {
- 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);
- }
- }
-
- public void replaceAll(UnaryOperator<E> operator) {
- 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);
+ @Override public boolean remove(Object object) {
+ synchronized (CopyOnWriteArrayList.this) {
+ int index = indexOf(object);
+ if (index == -1) {
+ return false;
}
- l.setArray(expectedArray = newElements);
+ remove(index);
+ return true;
}
}
- public void sort(Comparator<? super E> c) {
- 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);
+ @Override public boolean removeAll(Collection<?> collection) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkConcurrentModification(elements);
+ int removed = removeOrRetain(collection, false, slice.from, slice.to);
+ slice = new Slice(elements, slice.from, slice.to - removed);
+ return removed != 0;
}
}
- public boolean removeAll(Collection<?> c) {
- 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);
- }
- }
+ @Override public boolean retainAll(Collection<?> collection) {
+ synchronized (CopyOnWriteArrayList.this) {
+ slice.checkConcurrentModification(elements);
+ int removed = removeOrRetain(collection, true, slice.from, slice.to);
+ slice = new Slice(elements, slice.from, slice.to - removed);
+ return removed != 0;
}
- return removed;
}
-
- public boolean retainAll(Collection<?> c) {
- 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) {
- 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() {
- 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);
- }
-
}
- private static class COWSubListIterator<E> implements ListIterator<E> {
- private final ListIterator<E> it;
- private final int offset;
- private final int size;
+ static class Slice {
+ private final Object[] expectedElements;
+ private final int from;
+ private final int to;
- COWSubListIterator(List<E> l, int index, int offset, int size) {
- this.offset = offset;
- this.size = size;
- it = l.listIterator(index+offset);
+ Slice(Object[] expectedElements, int from, int to) {
+ this.expectedElements = expectedElements;
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * Throws if {@code index} doesn't identify an element in the array.
+ */
+ void checkElementIndex(int index) {
+ if (index < 0 || index >= to - from) {
+ throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
+ }
+ }
+
+ /**
+ * Throws if {@code index} doesn't identify an insertion point in the
+ * array. Unlike element index, it's okay to add or iterate at size().
+ */
+ void checkPositionIndex(int index) {
+ if (index < 0 || index > to - from) {
+ throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
+ }
+ }
+
+ void checkConcurrentModification(Object[] snapshot) {
+ if (expectedElements != snapshot) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+
+ /**
+ * Iterates an immutable snapshot of the list.
+ */
+ static class CowIterator<E> implements ListIterator<E> {
+ private final Object[] snapshot;
+ private final int from;
+ private final int to;
+ private int index = 0;
+
+ CowIterator(Object[] snapshot, int from, int to) {
+ this.snapshot = snapshot;
+ this.from = from;
+ this.to = to;
+ this.index = from;
+ }
+
+ public void add(E object) {
+ throw new UnsupportedOperationException();
}
public boolean hasNext() {
- return nextIndex() < size;
- }
-
- public E next() {
- if (hasNext())
- return it.next();
- else
- throw new NoSuchElementException();
+ return index < to;
}
public boolean hasPrevious() {
- return previousIndex() >= 0;
+ return index > from;
}
- public E previous() {
- if (hasPrevious())
- return it.previous();
- else
+ @SuppressWarnings("unchecked")
+ public E next() {
+ if (index < to) {
+ return (E) snapshot[index++];
+ } else {
throw new NoSuchElementException();
+ }
}
public int nextIndex() {
- return it.nextIndex() - offset;
+ return index;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E previous() {
+ if (index > from) {
+ return (E) snapshot[--index];
+ } else {
+ throw new NoSuchElementException();
+ }
}
public int previousIndex() {
- return it.previousIndex() - offset;
+ return index - 1;
}
public void remove() {
throw new UnsupportedOperationException();
}
- public void set(E e) {
- throw new UnsupportedOperationException();
- }
-
- public void add(E e) {
+ public void set(E object) {
throw new UnsupportedOperationException();
}
@Override
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
- Objects.requireNonNull(action);
- while (nextIndex() < size) {
- action.accept(it.next());
+ java.util.Objects.requireNonNull(action);
+ Object[] elements = snapshot;
+ for (int i = index; i < to; i++) {
+ @SuppressWarnings("unchecked") E e = (E) elements[i];
+ action.accept(e);
}
+ index = to;
}
}
- // Support for resetting lock while deserializing
- private void resetLock() {
- U.putObjectVolatile(this, LOCK, new Object());
- }
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long LOCK;
- static {
- try {
- LOCK = U.objectFieldOffset
- (CopyOnWriteArrayList.class.getDeclaredField("lock"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ Object[] snapshot = elements;
+ out.defaultWriteObject();
+ out.writeInt(snapshot.length);
+ for (Object o : snapshot) {
+ out.writeObject(o);
}
}
+
+ private synchronized void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ Object[] snapshot = new Object[in.readInt()];
+ for (int i = 0; i < snapshot.length; i++) {
+ snapshot[i] = in.readObject();
+ }
+ elements = snapshot;
+ }
}
diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index 0cf8558..347ed14 100644
--- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -6,19 +6,10 @@
package java.util.concurrent;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
// END android-note
/**
@@ -44,12 +35,12 @@
* copy-on-write set to maintain a set of Handler objects that
* perform some action upon state updates.
*
- * <pre> {@code
+ * <pre> {@code
* class Handler { void handle(); ... }
*
* class X {
* private final CopyOnWriteArraySet<Handler> handlers
- * = new CopyOnWriteArraySet<>();
+ * = new CopyOnWriteArraySet<Handler>();
* public void addHandler(Handler h) { handlers.add(h); }
*
* private long internalState;
@@ -65,7 +56,7 @@
* @see CopyOnWriteArrayList
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this set
+ * @param <E> the type of elements held in this collection
*/
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
@@ -88,15 +79,8 @@
* @throws NullPointerException if the specified collection is null
*/
public CopyOnWriteArraySet(Collection<? extends E> c) {
- if (c.getClass() == CopyOnWriteArraySet.class) {
- @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
- (CopyOnWriteArraySet<E>)c;
- al = new CopyOnWriteArrayList<E>(cc.al);
- }
- else {
- al = new CopyOnWriteArrayList<E>();
- al.addAllAbsent(c);
- }
+ al = new CopyOnWriteArrayList<E>();
+ al.addAllAbsent(c);
}
/**
@@ -120,7 +104,8 @@
/**
* Returns {@code true} if this set contains the specified element.
* More formally, returns {@code true} if and only if this set
- * contains an element {@code e} such that {@code Objects.equals(o, e)}.
+ * contains an element {@code e} such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return {@code true} if this set contains the specified element
@@ -176,7 +161,7 @@
* The following code can be used to dump the set into a newly allocated
* array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -205,10 +190,11 @@
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element {@code e} such that
- * {@code Objects.equals(o, e)}, if this set contains such an element.
- * Returns {@code true} if this set contained the element (or
- * equivalently, if this set changed as a result of the call).
- * (This set will not contain the element once the call returns.)
+ * <tt>(o==null ? e==null : o.equals(e))</tt>,
+ * if this set contains such an element. Returns {@code true} if
+ * this set contained the element (or equivalently, if this set
+ * changed as a result of the call). (This set will not contain the
+ * element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return {@code true} if this set contained the specified element
@@ -221,7 +207,7 @@
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element {@code e} to this set if
* the set contains no element {@code e2} such that
- * {@code Objects.equals(e, e2)}.
+ * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.
*
@@ -245,44 +231,7 @@
* @see #contains(Object)
*/
public boolean containsAll(Collection<?> c) {
- return (c instanceof Set)
- ? compareSets(al.getArray(), (Set<?>) c) >= 0
- : al.containsAll(c);
- }
-
- /**
- * Tells whether the objects in snapshot (regarded as a set) are a
- * superset of the given set.
- *
- * @return -1 if snapshot is not a superset, 0 if the two sets
- * contain precisely the same elements, and 1 if snapshot is a
- * proper superset of the given set
- */
- private static int compareSets(Object[] snapshot, Set<?> set) {
- // Uses O(n^2) algorithm, that is only appropriate for small
- // sets, which CopyOnWriteArraySets should be.
- //
- // Optimize up to O(n) if the two sets share a long common prefix,
- // as might happen if one set was created as a copy of the other set.
-
- final int len = snapshot.length;
- // Mark matched elements to avoid re-checking
- final boolean[] matched = new boolean[len];
-
- // j is the largest int with matched[i] true for { i | 0 <= i < j }
- int j = 0;
- outer: for (Object x : set) {
- for (int i = j; i < len; i++) {
- if (!matched[i] && Objects.equals(x, snapshot[i])) {
- matched[i] = true;
- if (i == j)
- do { j++; } while (j < len && matched[j]);
- continue outer;
- }
- }
- return -1;
- }
- return (j == len) ? 0 : 1;
+ return al.containsAll(c);
}
/**
@@ -311,11 +260,9 @@
* @param c collection containing elements to be removed from this set
* @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="../Collection.html#optional-restrictions">optional</a>)
+ * is incompatible with the specified collection (optional)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * specified collection does not permit null elements (optional),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -334,11 +281,9 @@
* @param c collection containing elements to be retained in this set
* @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="../Collection.html#optional-restrictions">optional</a>)
+ * is incompatible with the specified collection (optional)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * specified collection does not permit null elements (optional),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -365,49 +310,54 @@
* Compares the specified object with this set for equality.
* Returns {@code true} if the specified object is the same object
* as this object, or if it is also a {@link Set} and the elements
- * returned by an {@linkplain Set#iterator() iterator} over the
+ * returned by an {@linkplain List#iterator() iterator} over the
* specified set are the same as the elements returned by an
* iterator over this set. More formally, the two iterators are
* considered to return the same elements if they return the same
* number of elements and for every element {@code e1} returned by
* the iterator over the specified set, there is an element
* {@code e2} returned by the iterator over this set such that
- * {@code Objects.equals(e1, e2)}.
+ * {@code (e1==null ? e2==null : e1.equals(e2))}.
*
* @param o object to be compared for equality with this set
* @return {@code true} if the specified object is equal to this set
*/
public boolean equals(Object o) {
- return (o == this)
- || ((o instanceof Set)
- && compareSets(al.getArray(), (Set<?>) o) == 0);
- }
+ if (o == this)
+ return true;
+ if (!(o instanceof Set))
+ return false;
+ Set<?> set = (Set<?>)(o);
+ Iterator<?> it = set.iterator();
- public boolean removeIf(Predicate<? super E> filter) {
- return al.removeIf(filter);
- }
+ // Uses O(n^2) algorithm that is only appropriate
+ // for small sets, which CopyOnWriteArraySets should be.
- public void forEach(Consumer<? super E> action) {
- al.forEach(action);
+ // Use a single snapshot of underlying array
+ Object[] elements = al.getArray();
+ int len = elements.length;
+ // Mark matched elements to avoid re-checking
+ boolean[] matched = new boolean[len];
+ int k = 0;
+ outer: while (it.hasNext()) {
+ if (++k > len)
+ return false;
+ Object x = it.next();
+ for (int i = 0; i < len; ++i) {
+ if (!matched[i] && eq(x, elements[i])) {
+ matched[i] = true;
+ continue outer;
+ }
+ }
+ return false;
+ }
+ return k == len;
}
/**
- * Returns a {@link Spliterator} over the elements in this set in the order
- * in which these elements were added.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
- * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
- * {@link Spliterator#SUBSIZED}.
- *
- * <p>The spliterator provides a snapshot of the state of the set
- * when the spliterator was constructed. No synchronization is needed while
- * operating on the spliterator.
- *
- * @return a {@code Spliterator} over the elements in this set
- * @since 1.8
+ * Tests for equality, coping with nulls.
*/
- public Spliterator<E> spliterator() {
- return Spliterators.spliterator
- (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
+ private static boolean eq(Object o1, Object o2) {
+ return (o1 == null) ? o2 == null : o1.equals(o2);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/CountDownLatch.java b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
index 680ea16..77093f7 100644
--- a/luni/src/main/java/java/util/concurrent/CountDownLatch.java
+++ b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
@@ -44,7 +44,7 @@
* until all workers have completed.
* </ul>
*
- * <pre> {@code
+ * <pre> {@code
* class Driver { // ...
* void main() throws InterruptedException {
* CountDownLatch startSignal = new CountDownLatch(1);
@@ -85,7 +85,7 @@
* will be able to pass through await. (When threads must repeatedly
* count down in this way, instead use a {@link CyclicBarrier}.)
*
- * <pre> {@code
+ * <pre> {@code
* class Driver2 { // ...
* void main() throws InterruptedException {
* CountDownLatch doneSignal = new CountDownLatch(N);
@@ -151,7 +151,7 @@
int c = getState();
if (c == 0)
return false;
- int nextc = c - 1;
+ int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
diff --git a/luni/src/main/java/java/util/concurrent/CountedCompleter.java b/luni/src/main/java/java/util/concurrent/CountedCompleter.java
index 9c8b1b2..b868037 100644
--- a/luni/src/main/java/java/util/concurrent/CountedCompleter.java
+++ b/luni/src/main/java/java/util/concurrent/CountedCompleter.java
@@ -13,7 +13,7 @@
* presence of subtask stalls and blockage than are other forms of
* ForkJoinTasks, but are less intuitive to program. Uses of
* CountedCompleter are similar to those of other completion based
- * components
+ * components (such as {@link java.nio.channels.CompletionHandler})
* except that multiple <em>pending</em> completions may be necessary
* to trigger the completion action {@link #onCompletion(CountedCompleter)},
* not just one.
@@ -139,8 +139,7 @@
* {@code tryComplete}) the pending count is set to one:
*
* <pre> {@code
- * class ForEach<E> ... {
- * ...
+ * class ForEach<E> ...
* public void compute() { // version 2
* if (hi - lo >= 2) {
* int mid = (lo + hi) >>> 1;
@@ -154,19 +153,18 @@
* tryComplete();
* }
* }
- * }}</pre>
+ * }</pre>
*
- * As a further optimization, notice that the left task need not even exist.
+ * As a further improvement, 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> ... {
- * ...
+ * class ForEach<E> ...
* public void compute() { // version 3
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
@@ -177,9 +175,9 @@
* op.apply(array[l]);
* propagateCompletion();
* }
- * }}</pre>
+ * }</pre>
*
- * Additional optimizations of such classes might entail precomputing
+ * Additional improvements 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
@@ -206,7 +204,7 @@
* }
* public E getRawResult() { return result.get(); }
* public void compute() { // similar to ForEach version 3
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (result.get() == null && h >= l) {
* if (h - l >= 2) {
* int mid = (l + h) >>> 1;
@@ -231,9 +229,9 @@
* }}</pre>
*
* In this example, as well as others in which tasks have no other
- * effects except to {@code compareAndSet} a common result, the
- * trailing unconditional invocation of {@code tryComplete} could be
- * made conditional ({@code if (result.get() == null) tryComplete();})
+ * effects except to compareAndSet a common result, the trailing
+ * unconditional invocation of {@code tryComplete} could be made
+ * conditional ({@code if (result.get() == null) tryComplete();})
* because no further bookkeeping is required to manage completions
* once the root task completes.
*
@@ -336,7 +334,7 @@
* this.next = next;
* }
* public void compute() {
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
@@ -347,7 +345,7 @@
* result = mapper.apply(array[l]);
* // process completions by reducing along and advancing subtask links
* for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
- * for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
+ * for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
* t.result = reducer.apply(t.result, s.result);
* }
* }
@@ -375,9 +373,11 @@
* // sample use:
* PacketSender p = new PacketSender();
* new HeaderBuilder(p, ...).fork();
- * new BodyBuilder(p, ...).fork();}</pre>
+ * new BodyBuilder(p, ...).fork();
+ * }</pre>
*
* @since 1.8
+ * @hide
* @author Doug Lea
*/
public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
@@ -495,7 +495,8 @@
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
- U.getAndAddInt(this, PENDING, delta);
+ int c;
+ do {} while (!U.compareAndSwapInt(this, PENDING, c = pending, c+delta));
}
/**
@@ -595,7 +596,7 @@
* any one (versus all) of several subtask results are obtained.
* However, in the common (and recommended) case in which {@code
* setRawResult} is not overridden, this effect can be obtained
- * more simply using {@link #quietlyCompleteRoot()}.
+ * more simply using {@code quietlyCompleteRoot();}.
*
* @param rawResult the raw result
*/
@@ -610,9 +611,9 @@
/**
* If this task's pending count is zero, returns this task;
- * otherwise decrements its pending count and returns {@code null}.
- * This method is designed to be used with {@link #nextComplete} in
- * completion traversal loops.
+ * otherwise decrements its pending count and returns {@code
+ * null}. This method is designed to be used with {@link
+ * #nextComplete} in completion traversal loops.
*
* @return this task, if pending count was zero, else {@code null}
*/
@@ -666,26 +667,6 @@
}
/**
- * If this task has not completed, attempts to process at most the
- * given number of other unprocessed tasks for which this task is
- * on the completion path, if any are known to exist.
- *
- * @param maxTasks the maximum number of tasks to process. If
- * less than or equal to zero, then no tasks are
- * processed.
- */
- public final void helpComplete(int maxTasks) {
- Thread t; ForkJoinWorkerThread wt;
- if (maxTasks > 0 && status >= 0) {
- if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
- (wt = (ForkJoinWorkerThread)t).pool.
- helpComplete(wt.workQueue, this, maxTasks);
- else
- ForkJoinPool.common.externalHelpComplete(this, maxTasks);
- }
- }
-
- /**
* Supports ForkJoinTask exception propagation.
*/
void internalPropagateException(Throwable ex) {
@@ -725,13 +706,14 @@
protected void setRawResult(T t) { }
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
private static final long PENDING;
static {
try {
+ U = sun.misc.Unsafe.getUnsafe();
PENDING = U.objectFieldOffset
(CountedCompleter.class.getDeclaredField("pending"));
- } catch (ReflectiveOperationException e) {
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
index 7219c93..d698501 100644
--- a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -23,10 +23,10 @@
* This <em>barrier action</em> is useful
* for updating shared-state before any of the parties continue.
*
- * <p><b>Sample usage:</b> Here is an example of using a barrier in a
- * parallel decomposition design:
+ * <p><b>Sample usage:</b> Here is an example of
+ * using a barrier in a parallel decomposition design:
*
- * <pre> {@code
+ * <pre> {@code
* class Solver {
* final int N;
* final float[][] data;
@@ -53,20 +53,16 @@
* public Solver(float[][] matrix) {
* data = matrix;
* N = matrix.length;
- * Runnable barrierAction =
- * new Runnable() { public void run() { mergeRows(...); }};
- * barrier = new CyclicBarrier(N, barrierAction);
+ * barrier = new CyclicBarrier(N,
+ * new Runnable() {
+ * public void run() {
+ * mergeRows(...);
+ * }
+ * });
+ * for (int i = 0; i < N; ++i)
+ * new Thread(new Worker(i)).start();
*
- * List<Thread> threads = new ArrayList<>(N);
- * for (int i = 0; i < N; i++) {
- * Thread thread = new Thread(new Worker(i));
- * threads.add(thread);
- * thread.start();
- * }
- *
- * // wait until done
- * for (Thread thread : threads)
- * thread.join();
+ * waitUntilDone();
* }
* }}</pre>
*
@@ -83,7 +79,7 @@
* {@link #await} returns the arrival index of that thread at the barrier.
* You can then choose which thread should execute the barrier action, for
* example:
- * <pre> {@code
+ * <pre> {@code
* if (barrier.await() == 0) {
* // log the completion of this iteration
* }}</pre>
@@ -121,7 +117,7 @@
* but no subsequent reset.
*/
private static class Generation {
- boolean broken; // initially false
+ boolean broken = false;
}
/** The lock for guarding barrier entry */
@@ -392,8 +388,7 @@
* to arrive and zero indicates the last to arrive
* @throws InterruptedException if the current thread was interrupted
* while waiting
- * @throws TimeoutException if the specified timeout elapses.
- * In this case the barrier will be broken.
+ * @throws TimeoutException if the specified timeout elapses
* @throws BrokenBarrierException if <em>another</em> thread was
* interrupted or timed out while the current thread was
* waiting, or the barrier was reset, or the barrier was broken
diff --git a/luni/src/main/java/java/util/concurrent/DelayQueue.java b/luni/src/main/java/java/util/concurrent/DelayQueue.java
index d100a9c..e4a715e 100644
--- a/luni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/luni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -7,14 +7,9 @@
package java.util.concurrent;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-import java.util.AbstractQueue;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
@@ -42,7 +37,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
@@ -162,9 +157,10 @@
lock.lock();
try {
E first = q.peek();
- return (first == null || first.getDelay(NANOSECONDS) > 0)
- ? null
- : q.poll();
+ if (first == null || first.getDelay(NANOSECONDS) > 0)
+ return null;
+ else
+ return q.poll();
} finally {
lock.unlock();
}
@@ -187,7 +183,7 @@
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0L)
+ if (delay <= 0)
return q.poll();
first = null; // don't retain ref while waiting
if (leader != null)
@@ -229,15 +225,15 @@
for (;;) {
E first = q.peek();
if (first == null) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
else
nanos = available.awaitNanos(nanos);
} else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0L)
+ if (delay <= 0)
return q.poll();
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
first = null; // don't retain ref while waiting
if (nanos < delay || leader != null)
@@ -466,7 +462,7 @@
}
/**
- * Identity-based version for use in Itr.remove.
+ * Identity-based version for use in Itr.remove
*/
void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
@@ -488,8 +484,12 @@
* unexpired) in this queue. The iterator does not return the
* elements in any particular order.
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this queue
*/
diff --git a/luni/src/main/java/java/util/concurrent/Exchanger.java b/luni/src/main/java/java/util/concurrent/Exchanger.java
index 5f4c534..60871b4 100644
--- a/luni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/luni/src/main/java/java/util/concurrent/Exchanger.java
@@ -21,9 +21,9 @@
* to swap buffers between threads so that the thread filling the
* buffer gets a freshly emptied one when it needs it, handing off the
* filled one to the thread emptying the buffer.
- * <pre> {@code
+ * <pre> {@code
* class FillAndEmpty {
- * Exchanger<DataBuffer> exchanger = new Exchanger<>();
+ * Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
* DataBuffer initialEmptyBuffer = ... a made-up type
* DataBuffer initialFullBuffer = ...
*
@@ -125,10 +125,9 @@
* writing, there is no way to determine cacheline size, we define
* 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,
- * and reworking some park/unpark mechanics compared to
- * LockSupport versions.
+ * sharing and to enhance locality, including adding padding 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
@@ -275,9 +274,8 @@
/**
* Nodes hold partially exchanged data, plus other per-thread
- * bookkeeping. Padded via @Contended to reduce memory contention.
+ * bookkeeping.
*/
- //@jdk.internal.vm.annotation.Contended // android-removed
static final class Node {
int index; // Arena index
int bound; // Last recorded value of Exchanger.bound
@@ -286,6 +284,10 @@
Object item; // This thread's current item
volatile Object match; // Item provided by releasing thread
volatile Thread parked; // Set to this thread when parked, else null
+
+ // Padding to ameliorate unfortunate memory placements
+ Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf;
+ Object q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe, qf;
}
/** The corresponding thread local class */
@@ -294,7 +296,7 @@
}
/**
- * Per-thread state.
+ * Per-thread state
*/
private final Participant participant;
@@ -596,33 +598,37 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
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 {
+ int s;
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> ek = Exchanger.class;
+ Class<?> nk = Node.class;
+ Class<?> ak = Node[].class;
+ Class<?> tk = Thread.class;
BOUND = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("bound"));
+ (ek.getDeclaredField("bound"));
SLOT = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("slot"));
-
+ (ek.getDeclaredField("slot"));
MATCH = U.objectFieldOffset
- (Node.class.getDeclaredField("match"));
-
+ (nk.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");
+ (tk.getDeclaredField("parkBlocker"));
+ s = U.arrayIndexScale(ak);
// ABASE absorbs padding in front of element 0
- ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
- } catch (ReflectiveOperationException e) {
+ ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT);
+
+ } catch (Exception e) {
throw new Error(e);
}
+ if ((s & (s-1)) != 0 || s > (1 << ASHIFT))
+ throw new Error("Unsupported array scale");
}
}
diff --git a/luni/src/main/java/java/util/concurrent/Executor.java b/luni/src/main/java/java/util/concurrent/Executor.java
index 9dd3efb..095ebfc 100644
--- a/luni/src/main/java/java/util/concurrent/Executor.java
+++ b/luni/src/main/java/java/util/concurrent/Executor.java
@@ -15,28 +15,30 @@
* invoking {@code new Thread(new RunnableTask()).start()} for each
* of a set of tasks, you might use:
*
- * <pre> {@code
- * Executor executor = anExecutor();
+ * <pre>
+ * Executor executor = <em>anExecutor</em>;
* executor.execute(new RunnableTask1());
* executor.execute(new RunnableTask2());
- * ...}</pre>
+ * ...
+ * </pre>
*
- * However, the {@code Executor} interface does not strictly require
- * that execution be asynchronous. In the simplest case, an executor
- * can run the submitted task immediately in the caller's thread:
+ * However, the {@code Executor} interface does not strictly
+ * require that execution be asynchronous. In the simplest case, an
+ * executor can run the submitted task immediately in the caller's
+ * thread:
*
- * <pre> {@code
+ * <pre> {@code
* class DirectExecutor implements Executor {
* public void execute(Runnable r) {
* r.run();
* }
* }}</pre>
*
- * More typically, tasks are executed in some thread other than the
- * caller's thread. The executor below spawns a new thread for each
- * task.
+ * More typically, tasks are executed in some thread other
+ * than the caller's thread. The executor below spawns a new thread
+ * for each task.
*
- * <pre> {@code
+ * <pre> {@code
* class ThreadPerTaskExecutor implements Executor {
* public void execute(Runnable r) {
* new Thread(r).start();
@@ -48,7 +50,7 @@
* serializes the submission of tasks to a second executor,
* illustrating a composite executor.
*
- * <pre> {@code
+ * <pre> {@code
* class SerialExecutor implements Executor {
* final Queue<Runnable> tasks = new ArrayDeque<>();
* final Executor executor;
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index cea0384..9514246 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -27,16 +27,16 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException, ExecutionException {
- * 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);
- * }
+ * 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);
+ * }
* }}</pre>
*
* Suppose instead that you would like to use the first non-null result
@@ -47,31 +47,32 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException {
- * CompletionService<Result> ecs
- * = new ExecutorCompletionService<Result>(e);
- * int n = solvers.size();
- * List<Future<Result>> futures = new ArrayList<>(n);
- * Result result = null;
- * try {
- * for (Callable<Result> s : solvers)
- * futures.add(ecs.submit(s));
- * for (int i = 0; i < n; ++i) {
- * try {
- * Result r = ecs.take().get();
- * if (r != null) {
- * result = r;
- * break;
+ * CompletionService<Result> ecs
+ * = new ExecutorCompletionService<Result>(e);
+ * int n = solvers.size();
+ * List<Future<Result>> futures
+ * = new ArrayList<Future<Result>>(n);
+ * Result result = null;
+ * try {
+ * for (Callable<Result> s : solvers)
+ * futures.add(ecs.submit(s));
+ * for (int i = 0; i < n; ++i) {
+ * try {
+ * Result r = ecs.take().get();
+ * if (r != null) {
+ * result = r;
+ * break;
+ * }
+ * } catch (ExecutionException ignore) {}
* }
- * } catch (ExecutionException ignore) {}
* }
- * }
- * finally {
- * for (Future<Result> f : futures)
- * f.cancel(true);
- * }
+ * finally {
+ * for (Future<Result> f : futures)
+ * f.cancel(true);
+ * }
*
- * if (result != null)
- * use(result);
+ * if (result != null)
+ * use(result);
* }}</pre>
*/
public class ExecutorCompletionService<V> implements CompletionService<V> {
@@ -80,18 +81,15 @@
private final BlockingQueue<Future<V>> completionQueue;
/**
- * FutureTask extension to enqueue upon completion.
+ * FutureTask extension to enqueue upon completion
*/
- private static class QueueingFuture<V> extends FutureTask<Void> {
- QueueingFuture(RunnableFuture<V> task,
- BlockingQueue<Future<V>> completionQueue) {
+ private class QueueingFuture extends FutureTask<Void> {
+ QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
- this.completionQueue = completionQueue;
}
- private final Future<V> task;
- private final BlockingQueue<Future<V>> completionQueue;
protected void done() { completionQueue.add(task); }
+ private final Future<V> task;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
@@ -151,14 +149,14 @@
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
- executor.execute(new QueueingFuture<V>(f, completionQueue));
+ executor.execute(new QueueingFuture(f));
return f;
}
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
- executor.execute(new QueueingFuture<V>(f, completionQueue));
+ executor.execute(new QueueingFuture(f));
return f;
}
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorService.java b/luni/src/main/java/java/util/concurrent/ExecutorService.java
index ce7b2c6..58a2113 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorService.java
@@ -6,8 +6,8 @@
package java.util.concurrent;
-import java.util.Collection;
import java.util.List;
+import java.util.Collection;
// BEGIN android-note
// removed security manager docs
@@ -47,7 +47,7 @@
* pool service incoming requests. It uses the preconfigured {@link
* Executors#newFixedThreadPool} factory method:
*
- * <pre> {@code
+ * <pre> {@code
* class NetworkService implements Runnable {
* private final ServerSocket serverSocket;
* private final ExecutorService pool;
@@ -81,7 +81,7 @@
* first by calling {@code shutdown} to reject incoming tasks, and then
* calling {@code shutdownNow}, if necessary, to cancel any lingering tasks:
*
- * <pre> {@code
+ * <pre> {@code
* void shutdownAndAwaitTermination(ExecutorService pool) {
* pool.shutdown(); // Disable new tasks from being submitted
* try {
diff --git a/luni/src/main/java/java/util/concurrent/Executors.java b/luni/src/main/java/java/util/concurrent/Executors.java
index 3d49b82..2068fd7 100644
--- a/luni/src/main/java/java/util/concurrent/Executors.java
+++ b/luni/src/main/java/java/util/concurrent/Executors.java
@@ -6,21 +6,17 @@
package java.util.concurrent;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
import java.security.AccessControlContext;
-import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import sun.security.util.SecurityConstants;
+import java.security.PrivilegedActionException;
// BEGIN android-note
// removed security manager docs
// END android-note
-
/**
* Factory and utility methods for {@link Executor}, {@link
* ExecutorService}, {@link ScheduledExecutorService}, {@link
@@ -28,18 +24,18 @@
* package. This class supports the following kinds of methods:
*
* <ul>
- * <li>Methods that create and return an {@link ExecutorService}
- * set up with commonly useful configuration settings.
- * <li>Methods that create and return a {@link ScheduledExecutorService}
- * set up with commonly useful configuration settings.
- * <li>Methods that create and return a "wrapped" ExecutorService, that
- * disables reconfiguration by making implementation-specific methods
- * inaccessible.
- * <li>Methods that create and return a {@link ThreadFactory}
- * that sets newly created threads to a known state.
- * <li>Methods that create and return a {@link Callable}
- * out of other closure-like forms, so they can be used
- * in execution methods requiring {@code Callable}.
+ * <li> Methods that create and return an {@link ExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li> Methods that create and return a {@link ScheduledExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li> Methods that create and return a "wrapped" ExecutorService, that
+ * disables reconfiguration by making implementation-specific methods
+ * inaccessible.
+ * <li> Methods that create and return a {@link ThreadFactory}
+ * that sets newly created threads to a known state.
+ * <li> Methods that create and return a {@link Callable}
+ * out of other closure-like forms, so they can be used
+ * in execution methods requiring {@code Callable}.
* </ul>
*
* @since 1.5
@@ -82,6 +78,7 @@
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code parallelism <= 0}
* @since 1.8
+ * @hide
*/
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
@@ -91,13 +88,12 @@
}
/**
- * Creates a work-stealing thread pool using the number of
- * {@linkplain Runtime#availableProcessors available processors}
+ * Creates a work-stealing thread pool using all
+ * {@link Runtime#availableProcessors available processors}
* as its target parallelism level.
- *
* @return the newly created thread pool
- * @see #newWorkStealingPool(int)
* @since 1.8
+ * @hide
*/
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
@@ -415,11 +411,11 @@
// Non-public classes supporting the public methods
/**
- * A callable that runs given task and returns given result.
+ * A callable that runs given task and returns given result
*/
- private static final class RunnableAdapter<T> implements Callable<T> {
- private final Runnable task;
- private final T result;
+ static final class RunnableAdapter<T> implements Callable<T> {
+ final Runnable task;
+ final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
@@ -431,11 +427,11 @@
}
/**
- * A callable that runs under established access control settings.
+ * A callable that runs under established access control settings
*/
- private static final class PrivilegedCallable<T> implements Callable<T> {
- final Callable<T> task;
- final AccessControlContext acc;
+ static final class PrivilegedCallable<T> implements Callable<T> {
+ private final Callable<T> task;
+ private final AccessControlContext acc;
PrivilegedCallable(Callable<T> task) {
this.task = task;
@@ -458,13 +454,12 @@
/**
* A callable that runs under established access control settings and
- * current ClassLoader.
+ * current ClassLoader
*/
- private static final class PrivilegedCallableUsingCurrentClassLoader<T>
- implements Callable<T> {
- final Callable<T> task;
- final AccessControlContext acc;
- final ClassLoader ccl;
+ static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> {
+ private final Callable<T> task;
+ private final AccessControlContext acc;
+ private final ClassLoader ccl;
PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
// BEGIN android-removed
@@ -474,7 +469,7 @@
// // never trigger a security check, but we check
// // whether our callers have this permission anyways.
// sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-
+ //
// // Whether setContextClassLoader turns out to be necessary
// // or not, we fail fast if permission is not available.
// sm.checkPermission(new RuntimePermission("setContextClassLoader"));
@@ -511,9 +506,9 @@
}
/**
- * The default thread factory.
+ * The default thread factory
*/
- private static class DefaultThreadFactory implements ThreadFactory {
+ static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
@@ -541,11 +536,11 @@
}
/**
- * Thread factory capturing access control context and class loader.
+ * Thread factory capturing access control context and class loader
*/
- private static class PrivilegedThreadFactory extends DefaultThreadFactory {
- final AccessControlContext acc;
- final ClassLoader ccl;
+ static class PrivilegedThreadFactory extends DefaultThreadFactory {
+ private final AccessControlContext acc;
+ private final ClassLoader ccl;
PrivilegedThreadFactory() {
super();
@@ -556,7 +551,7 @@
// // never trigger a security check, but we check
// // whether our callers have this permission anyways.
// sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-
+ //
// // Fail fast
// sm.checkPermission(new RuntimePermission("setContextClassLoader"));
// }
@@ -584,8 +579,7 @@
* A wrapper class that exposes only the ExecutorService methods
* of an ExecutorService implementation.
*/
- private static class DelegatedExecutorService
- extends AbstractExecutorService {
+ static class DelegatedExecutorService extends AbstractExecutorService {
private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
public void execute(Runnable command) { e.execute(command); }
@@ -626,8 +620,8 @@
}
}
- private static class FinalizableDelegatedExecutorService
- extends DelegatedExecutorService {
+ static class FinalizableDelegatedExecutorService
+ extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
@@ -640,7 +634,7 @@
* A wrapper class that exposes only the ScheduledExecutorService
* methods of a ScheduledExecutorService implementation.
*/
- private static class DelegatedScheduledExecutorService
+ static class DelegatedScheduledExecutorService
extends DelegatedExecutorService
implements ScheduledExecutorService {
private final ScheduledExecutorService e;
diff --git a/luni/src/main/java/java/util/concurrent/Flow.java b/luni/src/main/java/java/util/concurrent/Flow.java
deleted file mode 100644
index 75425f6..0000000
--- a/luni/src/main/java/java/util/concurrent/Flow.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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;
-
-/**
- * Interrelated interfaces and static methods for establishing
- * flow-controlled components in which {@link Publisher Publishers}
- * produce items consumed by one or more {@link Subscriber
- * Subscribers}, each managed by a {@link Subscription
- * Subscription}.
- *
- * <p>These interfaces correspond to the <a
- * href="http://www.reactive-streams.org/"> reactive-streams</a>
- * specification. They apply in both concurrent and distributed
- * asynchronous settings: All (seven) methods are defined in {@code
- * void} "one-way" message style. Communication relies on a simple form
- * of flow control (method {@link Subscription#request}) that can be
- * used to avoid resource management problems that may otherwise occur
- * in "push" based systems.
- *
- * <p><b>Examples.</b> A {@link Publisher} usually defines its own
- * {@link Subscription} implementation; constructing one in method
- * {@code subscribe} and issuing it to the calling {@link
- * Subscriber}. It publishes items to the subscriber asynchronously,
- * normally using an {@link Executor}. For example, here is a very
- * simple publisher that only issues (when requested) a single {@code
- * TRUE} item to a single subscriber. Because the subscriber receives
- * only a single item, this class does not use buffering and ordering
- * control required in most implementations (for example {@link
- * SubmissionPublisher}).
- *
- * <pre> {@code
- * class OneShotPublisher implements Publisher<Boolean> {
- * private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
- * private boolean subscribed; // true after first subscribe
- * public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
- * if (subscribed)
- * subscriber.onError(new IllegalStateException()); // only one allowed
- * else {
- * subscribed = true;
- * subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
- * }
- * }
- * static class OneShotSubscription implements Subscription {
- * private final Subscriber<? super Boolean> subscriber;
- * private final ExecutorService executor;
- * private Future<?> future; // to allow cancellation
- * private boolean completed;
- * OneShotSubscription(Subscriber<? super Boolean> subscriber,
- * ExecutorService executor) {
- * this.subscriber = subscriber;
- * this.executor = executor;
- * }
- * public synchronized void request(long n) {
- * if (n != 0 && !completed) {
- * completed = true;
- * if (n < 0) {
- * IllegalArgumentException ex = new IllegalArgumentException();
- * executor.execute(() -> subscriber.onError(ex));
- * } else {
- * future = executor.submit(() -> {
- * subscriber.onNext(Boolean.TRUE);
- * subscriber.onComplete();
- * });
- * }
- * }
- * }
- * public synchronized void cancel() {
- * completed = true;
- * if (future != null) future.cancel(false);
- * }
- * }
- * }}</pre>
- *
- * <p>A {@link Subscriber} arranges that items be requested and
- * processed. Items (invocations of {@link Subscriber#onNext}) are
- * not issued unless requested, but multiple items may be requested.
- * Many Subscriber implementations can arrange this in the style of
- * the following example, where a buffer size of 1 single-steps, and
- * larger sizes usually allow for more efficient overlapped processing
- * with less communication; for example with a value of 64, this keeps
- * total outstanding requests between 32 and 64.
- * Because Subscriber method invocations for a given {@link
- * Subscription} are strictly ordered, there is no need for these
- * methods to use locks or volatiles unless a Subscriber maintains
- * multiple Subscriptions (in which case it is better to instead
- * define multiple Subscribers, each with its own Subscription).
- *
- * <pre> {@code
- * class SampleSubscriber<T> implements Subscriber<T> {
- * final Consumer<? super T> consumer;
- * Subscription subscription;
- * final long bufferSize;
- * long count;
- * SampleSubscriber(long bufferSize, Consumer<? super T> consumer) {
- * this.bufferSize = bufferSize;
- * this.consumer = consumer;
- * }
- * public void onSubscribe(Subscription subscription) {
- * long initialRequestSize = bufferSize;
- * count = bufferSize - bufferSize / 2; // re-request when half consumed
- * (this.subscription = subscription).request(initialRequestSize);
- * }
- * public void onNext(T item) {
- * if (--count <= 0)
- * subscription.request(count = bufferSize - bufferSize / 2);
- * consumer.accept(item);
- * }
- * public void onError(Throwable ex) { ex.printStackTrace(); }
- * public void onComplete() {}
- * }}</pre>
- *
- * <p>The default value of {@link #defaultBufferSize} may provide a
- * useful starting point for choosing request sizes and capacities in
- * Flow components based on expected rates, resources, and usages.
- * Or, when flow control is never needed, a subscriber may initially
- * request an effectively unbounded number of items, as in:
- *
- * <pre> {@code
- * class UnboundedSubscriber<T> implements Subscriber<T> {
- * public void onSubscribe(Subscription subscription) {
- * subscription.request(Long.MAX_VALUE); // effectively unbounded
- * }
- * public void onNext(T item) { use(item); }
- * public void onError(Throwable ex) { ex.printStackTrace(); }
- * public void onComplete() {}
- * void use(T item) { ... }
- * }}</pre>
- *
- * @author Doug Lea
- * @since 9
- */
-public final class Flow {
-
- private Flow() {} // uninstantiable
-
- /**
- * A producer of items (and related control messages) received by
- * Subscribers. Each current {@link Subscriber} receives the same
- * items (via method {@code onNext}) in the same order, unless
- * drops or errors are encountered. If a Publisher encounters an
- * error that does not allow items to be issued to a Subscriber,
- * that Subscriber receives {@code onError}, and then receives no
- * further messages. Otherwise, when it is known that no further
- * messages will be issued to it, a subscriber receives {@code
- * onComplete}. Publishers ensure that Subscriber method
- * invocations for each subscription are strictly ordered in <a
- * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a>
- * order.
- *
- * <p>Publishers may vary in policy about whether drops (failures
- * to issue an item because of resource limitations) are treated
- * as unrecoverable errors. Publishers may also vary about
- * whether Subscribers receive items that were produced or
- * available before they subscribed.
- *
- * @param <T> the published item type
- */
- @FunctionalInterface
- public static interface Publisher<T> {
- /**
- * Adds the given Subscriber if possible. If already
- * subscribed, or the attempt to subscribe fails due to policy
- * violations or errors, the Subscriber's {@code onError}
- * method is invoked with an {@link IllegalStateException}.
- * Otherwise, the Subscriber's {@code onSubscribe} method is
- * invoked with a new {@link Subscription}. Subscribers may
- * enable receiving items by invoking the {@code request}
- * method of this Subscription, and may unsubscribe by
- * invoking its {@code cancel} method.
- *
- * @param subscriber the subscriber
- * @throws NullPointerException if subscriber is null
- */
- public void subscribe(Subscriber<? super T> subscriber);
- }
-
- /**
- * A receiver of messages. The methods in this interface are
- * invoked in strict sequential order for each {@link
- * Subscription}.
- *
- * @param <T> the subscribed item type
- */
- public static interface Subscriber<T> {
- /**
- * Method invoked prior to invoking any other Subscriber
- * methods for the given Subscription. If this method throws
- * an exception, resulting behavior is not guaranteed, but may
- * cause the Subscription not to be established or to be cancelled.
- *
- * <p>Typically, implementations of this method invoke {@code
- * subscription.request} to enable receiving items.
- *
- * @param subscription a new subscription
- */
- public void onSubscribe(Subscription subscription);
-
- /**
- * Method invoked with a Subscription's next item. If this
- * method throws an exception, resulting behavior is not
- * guaranteed, but may cause the Subscription to be cancelled.
- *
- * @param item the item
- */
- public void onNext(T item);
-
- /**
- * Method invoked upon an unrecoverable error encountered by a
- * Publisher or Subscription, after which no other Subscriber
- * methods are invoked by the Subscription. If this method
- * itself throws an exception, resulting behavior is
- * undefined.
- *
- * @param throwable the exception
- */
- public void onError(Throwable throwable);
-
- /**
- * Method invoked when it is known that no additional
- * Subscriber method invocations will occur for a Subscription
- * that is not already terminated by error, after which no
- * other Subscriber methods are invoked by the Subscription.
- * If this method throws an exception, resulting behavior is
- * undefined.
- */
- public void onComplete();
- }
-
- /**
- * Message control linking a {@link Publisher} and {@link
- * Subscriber}. Subscribers receive items only when requested,
- * and may cancel at any time. The methods in this interface are
- * intended to be invoked only by their Subscribers; usages in
- * other contexts have undefined effects.
- */
- public static interface Subscription {
- /**
- * Adds the given number {@code n} of items to the current
- * unfulfilled demand for this subscription. If {@code n} is
- * negative, the Subscriber will receive an {@code onError}
- * signal with an {@link IllegalArgumentException} argument.
- * Otherwise, the Subscriber will receive up to {@code n}
- * additional {@code onNext} invocations (or fewer if
- * terminated).
- *
- * @param n the increment of demand; a value of {@code
- * Long.MAX_VALUE} may be considered as effectively unbounded
- */
- public void request(long n);
-
- /**
- * Causes the Subscriber to (eventually) stop receiving
- * messages. Implementation is best-effort -- additional
- * messages may be received after invoking this method.
- * A cancelled subscription need not ever receive an
- * {@code onComplete} or {@code onError} signal.
- */
- public void cancel();
- }
-
- /**
- * A component that acts as both a Subscriber and Publisher.
- *
- * @param <T> the subscribed item type
- * @param <R> the published item type
- */
- public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
- }
-
- static final int DEFAULT_BUFFER_SIZE = 256;
-
- /**
- * Returns a default value for Publisher or Subscriber buffering,
- * that may be used in the absence of other constraints.
- *
- * @implNote
- * The current value returned is 256.
- *
- * @return the buffer size value
- */
- public static int defaultBufferSize() {
- return DEFAULT_BUFFER_SIZE;
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 184d07a..41dd161 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -7,16 +7,11 @@
package java.util.concurrent;
import java.lang.Thread.UncaughtExceptionHandler;
-import java.security.AccessControlContext;
-import java.security.Permissions;
-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.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.LockSupport;
/**
* An {@link ExecutorService} for running {@link ForkJoinTask}s.
@@ -36,7 +31,7 @@
* ForkJoinPool}s may also be appropriate for use with event-style
* tasks that are never joined.
*
- * <p>A static {@link #commonPool()} is available and appropriate for
+ * <p>A static {@code commonPool()} is available and appropriate for
* most applications. The common pool is used by any ForkJoinTask that
* is not explicitly submitted to a specified pool. Using the common
* pool normally reduces resource usage (its threads are slowly
@@ -45,9 +40,9 @@
*
* <p>For applications that require separate or custom pools, a {@code
* ForkJoinPool} may be constructed with a given target parallelism
- * level; by default, equal to the number of available processors.
- * The pool attempts to maintain enough active (or available) threads
- * by dynamically adding, suspending, or resuming internal worker
+ * level; by default, equal to the number of available processors. The
+ * pool attempts to maintain enough active (or available) threads by
+ * dynamically adding, suspending, or resuming internal worker
* threads, even if some tasks are stalled waiting to join others.
* However, no such adjustments are guaranteed in the face of blocked
* I/O or other unmanaged synchronization. The nested {@link
@@ -107,19 +102,12 @@
* - the class name of a {@link ForkJoinWorkerThreadFactory}
* <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
* - 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 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
- * using a factory that may return {@code null}. However doing so may
- * cause unjoined tasks to never be executed.
+ * using a factory that may return {@code null}.
*
* <p><b>Implementation notes</b>: This implementation restricts the
* maximum number of running threads to 32767. Attempts to create
@@ -133,7 +121,6 @@
* @since 1.7
* @author Doug Lea
*/
-//@jdk.internal.vm.annotation.Contended // android-removed
public class ForkJoinPool extends AbstractExecutorService {
/*
@@ -146,14 +133,7 @@
* 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.
+ * tasks in other queues.
*
* WorkQueues
* ==========
@@ -173,305 +153,200 @@
* (http://research.sun.com/scalable/pubs/index.html) and
* "Idempotent work stealing" by Michael, Saraswat, and Vechev,
* PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
- * The main differences ultimately stem from GC requirements that
- * we null out taken slots as soon as we can, to maintain as small
- * a footprint as possible even in programs generating huge
- * numbers of tasks. To accomplish this, we shift the CAS
- * arbitrating pop vs poll (steal) from being on the indices
- * ("base" and "top") to the slots themselves.
- *
- * Adding tasks then takes the form of a classic array push(task)
- * in a circular buffer:
- * q.array[q.top++ % length] = task;
- *
- * (The actual code needs to null-check and size-check the array,
- * uses masking, not mod, for indexing a power-of-two-sized array,
- * 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
- * (CAS slot to null))
- * decrement top and return task;
- *
- * And the poll operation (usually by a stealer) is
- * if ((the task at base slot is not null) and
- * (CAS slot to null))
- * increment base and return task;
- *
- * 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
+ * See also "Correct and Efficient Work-Stealing for Weak Memory
+ * Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
* (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
- * analysis of memory ordering requirements in work-stealing
- * 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 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.
+ * analysis of memory ordering (atomic, volatile etc) issues. The
+ * main differences ultimately stem from GC requirements that we
+ * null out taken slots as soon as we can, to maintain as small a
+ * footprint as possible even in programs generating huge numbers
+ * of tasks. To accomplish this, we shift the CAS arbitrating pop
+ * vs poll (steal) from being on the indices ("base" and "top") to
+ * the slots themselves. So, both a successful pop and poll
+ * mainly entail a CAS of a slot from non-null to null. Because
+ * we rely on CASes of references, we do not need tag bits on base
+ * or top. They are simple ints as used in any circular
+ * array-based queue (see for example ArrayDeque). Updates to the
+ * indices must still be ordered in a way that guarantees that top
+ * == base means the queue is empty, but otherwise may err on the
+ * side of possibly making the queue appear nonempty when a push,
+ * pop, or poll have not fully committed. Note that this means
+ * that 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) 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
+ * non-blockingness. If an attempted steal fails, a thief always
+ * 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. (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.)
+ * consider alternative actions, rather than method poll.)
*
- * This approach also enables support of a user mode in which
- * local task processing is in FIFO, not LIFO order, simply by
- * using poll rather than pop. This can be useful in
- * message-passing frameworks in which tasks are never joined.
+ * This approach also enables support of a user mode in which local
+ * task processing is in FIFO, not LIFO order, simply by using
+ * poll rather than pop. This can be useful in message-passing
+ * frameworks in which tasks are never joined. However neither
+ * mode considers affinities, loads, cache localities, etc, so
+ * rarely provide the best possible performance on a given
+ * machine, but portably provide good throughput by averaging over
+ * these factors. (Further, even if we did try to use such
+ * information, we do not usually have a basis for exploiting it.
+ * For example, some sets of tasks profit from cache affinities,
+ * but others are harmed by cache pollution effects.)
*
* WorkQueues are also used in a similar way for tasks submitted
* to the pool. We cannot mix these tasks in the same queues used
- * by workers. Instead, we randomly associate submission queues
+ * for work-stealing (this would contaminate lifo/fifo
+ * processing). Instead, we randomly associate submission queues
* with submitting threads, using a form of hashing. The
- * ThreadLocalRandom probe value serves as a hash code for
+ * Submitter probe value serves as a hash code for
* 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 (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
+ * tasks that they submitted. However, because most
+ * shared/external queue operations are more expensive than
+ * internal, and because, at steady state, external submitters
+ * will compete for CPU with workers, ForkJoinTask.join and
+ * related methods disable them from repeatedly helping to process
+ * tasks if all workers are active. Insertion of tasks in shared
+ * mode requires a lock (mainly to protect in the case of
+ * resizing) but we use only a simple spinlock (using bits in
* 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.
+ * creating and registering new queues.
*
* Management
* ==========
*
* The main throughput advantages of work-stealing stem from
* decentralized control -- workers mostly take tasks from
- * themselves or each other, at rates that can exceed a billion
- * per second. The pool itself creates, activates (enables
- * scanning for and running tasks), deactivates, blocks, and
- * terminates threads, all with minimal central information.
- * 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 two
- * volatile variables that are by far most often read (not
- * written) as status and consistency checks. (Also, field
- * "config" holds unchanging configuration state.)
+ * themselves or each other. We cannot negate this in the
+ * implementation of other management responsibilities. The main
+ * tactic for avoiding bottlenecks is packing nearly all
+ * essentially atomic control state into two volatile variables
+ * that are by far most often read (not written) as status and
+ * consistency checks.
*
- * Field "ctl" contains 64 bits holding information needed to
- * atomically decide to add, inactivate, enqueue (on an event
+ * Field "ctl" contains 64 bits holding all the information needed
+ * to 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.
+ * fields.
*
- * Field "runState" holds lifetime status, atomically and
- * monotonically setting STARTED, SHUTDOWN, STOP, and finally
- * TERMINATED bits.
+ * Field "plock" is a form of sequence lock with a saturating
+ * shutdown bit (similarly for per-queue "qlocks"), mainly
+ * protecting updates to the workQueues array, as well as to
+ * enable shutdown. When used as a lock, it is normally only very
+ * briefly held, so is nearly always available after at most a
+ * brief spin, but we use a monitor-based backup strategy to
+ * block when needed.
*
- * 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 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
+ * Recording WorkQueues. WorkQueues are recorded in the
+ * "workQueues" array that is created upon first use and expanded
+ * if necessary. Updates to the array while recording new workers
+ * and unrecording terminated ones are protected from each other
+ * by a lock but the array is otherwise concurrently readable, and
+ * accessed directly. 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
* compensation for blocked workers. However, all other support
* code is set up to work with other policies. To ensure that we
- * do not hold on to worker references that would prevent GC, all
+ * do not hold on to worker references that would prevent GC, ALL
* accesses to workQueues are via indices into the workQueues
* array (which is one source of some of the messy code
* constructions here). In essence, the workQueues array serves as
- * a weak reference mechanism. Thus for example the stack top
- * subfield of ctl stores indices, not references.
+ * a weak reference mechanism. Thus for example the wait queue
+ * field of ctl stores indices, not references. Access to the
+ * workQueues in associated methods (for example signalWork) must
+ * both index-check and null-check the IDs. All such accesses
+ * ignore bad IDs by returning out early from what they are doing,
+ * since this can only be associated with termination, in which
+ * case it is OK to give up. All uses of the workQueues array
+ * also check that it is non-null (even if previously
+ * non-null). This allows nulling during termination, which is
+ * currently not necessary, but remains an option for
+ * resource-revocation-based shutdown schemes. It also helps
+ * reduce JIT issuance of uncommon-trap code, which tends to
+ * unnecessarily complicate control flow in some methods.
*
- * Queuing Idle Workers. Unlike HPC work-stealing frameworks, we
- * cannot let workers spin indefinitely scanning for tasks when
- * none can be found immediately, and we cannot start/resume
- * 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
- * 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.
+ * Event Queuing. Unlike HPC work-stealing frameworks, we cannot
+ * let workers spin indefinitely scanning for tasks when none can
+ * be found immediately, and we cannot start/resume 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 to activate workers is
+ * the main limiting factor in overall performance (this is
+ * compounded at program start-up by JIT compilation and
+ * allocation). So we try to streamline this as much as possible.
+ * We park/unpark workers after placing in an event wait queue
+ * when they cannot find work. This "queue" is actually a simple
+ * Treiber stack, headed by the "id" field of ctl, plus a 15bit
+ * counter value (that reflects the number of times a worker has
+ * been inactivated) to avoid ABA effects (we need only as many
+ * version numbers as worker threads). Successors are held in
+ * field WorkQueue.nextWait. Queuing deals with several intrinsic
+ * races, mainly that a task-producing thread can miss seeing (and
+ * signalling) another thread that gave up looking for work but
+ * has not yet entered the wait queue. We solve this by requiring
+ * a full sweep of all workers (via repeated calls to method
+ * scan()) both before and after a newly waiting worker is added
+ * to the wait queue. Because enqueued workers may actually be
+ * rescanning rather than waiting, we set and clear the "parker"
+ * field of WorkQueues to reduce unnecessary calls to unpark.
+ * (This requires a secondary recheck to avoid missed signals.)
+ * Note the unusual conventions about Thread.interrupts
+ * surrounding parking and other blocking: Because interrupts are
+ * used solely to alert threads to check termination, which is
+ * checked anyway upon blocking, we clear status (using
+ * Thread.interrupted) before any call to park, so that park does
+ * not immediately return due to status being set via some other
+ * unrelated call to interrupt in user code.
*
- * 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. 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 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
- * (expanding the array if necessary). The thread is then started.
- * Upon any exception across these steps, or null return from
- * factory, deregisterWorker adjusts counts and records
- * accordingly. If a null return, the pool continues running with
- * fewer than the target number workers. If exceptional, the
- * exception is propagated, generally to some external caller.
- * Worker index assignment avoids the bias in scanning that would
- * occur if entries were sequentially packed starting at the front
- * of the workQueues array. We treat the array as a simple
- * power-of-two hash table, expanding as needed. The seedIndex
- * increment ensures no collisions until a resize is needed or a
- * worker is deregistered and replaced, and thereafter keeps
- * probability of collision low. We cannot use
- * ThreadLocalRandom.getProbe() for similar purposes here because
- * the thread has not started yet, but do so for creating
- * submission queues for existing external threads (see
- * externalPush).
- *
- * 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
- * synchronization surrounding activation. This uses a more
- * efficient version of a Dekker-like rule that task producers and
- * 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 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. 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() 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.
+ * Signalling. We create or wake up workers only when there
+ * appears to be at least one task they might be able to find and
+ * execute. When a submission is added or another worker adds a
+ * task to a queue that has fewer than two tasks, they signal
+ * waiting workers (or trigger creation of new ones if fewer than
+ * the given parallelism level -- signalWork). These primary
+ * signals are buttressed by others whenever other threads remove
+ * a task from a queue and notice that there are other tasks there
+ * as well. So in general, pools will be over-signalled. On most
+ * platforms, signalling (unpark) overhead time is noticeably
+ * long, and the time between signalling a thread and it actually
+ * making progress can be very noticeably long, so it is worth
+ * offloading these delays from critical paths as much as
+ * possible. Additionally, workers spin-down gradually, by staying
+ * alive so long as they see the ctl state changing. Similar
+ * stability-sensing techniques are also used before blocking in
+ * awaitJoin and helpComplete.
*
* 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 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.
+ * time out and terminate if the pool has remained quiescent for a
+ * given period -- a short period if there are more threads than
+ * parallelism, longer as the number of threads decreases. This
+ * will slowly propagate, eventually terminating all workers after
+ * periods of non-use.
*
- * 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 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.)
+ * Shutdown and Termination. A call to shutdownNow atomically sets
+ * a plock bit and then (non-atomically) sets each worker's
+ * qlock status, cancels all unprocessed tasks, and wakes up
+ * all waiting workers. Detecting whether termination should
+ * commence after a non-abrupt shutdown() call requires more work
+ * and bookkeeping. We need consensus about quiescence (i.e., that
+ * there is no more work). The active count provides a primary
+ * indication but non-abrupt shutdown still requires a rechecking
+ * scan for any workers that are inactive but not queued.
*
* Joining Tasks
* =============
@@ -482,9 +357,9 @@
* 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:
+ * possible is not necessarily a good idea since we sometimes 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.
@@ -504,16 +379,16 @@
* The ManagedBlocker extension API can't use helping so relies
* only on compensation in method awaitBlocker.
*
- * 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 &
+ * The algorithm in tryHelpStealer entails a form of "linear"
+ * helping: Each worker records (in field currentSteal) the most
+ * recent task it stole from some other worker. Plus, it records
+ * (in field currentJoin) the task it is currently actively
+ * joining. Method tryHelpStealer 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.
+ * In essence, the joiner executes a task that would be on its own
+ * local deque had the to-be-joined task not been stolen. This may
+ * be seen as a conservative variant of the approach 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
@@ -531,45 +406,31 @@
* 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
+ * to find work (see MAX_HELP) and fall back to suspending the
* worker and if necessary replacing it with another.
*
- * 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.
- * 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. 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.
+ * It is impossible to keep exactly the target parallelism number
+ * of threads running at any given time. Determining the
+ * existence of conservatively safe helping targets, the
+ * availability of already-created spares, and the apparent need
+ * to create new spares are all racy, so we rely on multiple
+ * retries of each. Compensation in the apparent absence of
+ * helping opportunities is challenging to control on JVMs, where
+ * GC and other activities can stall progress of tasks that in
+ * turn stall out many other dependent tasks, without us being
+ * able to determine whether they will ever require compensation.
+ * Even though work-stealing otherwise encounters little
+ * degradation in the presence of more threads than cores,
+ * aggressively adding new threads in such cases entails risk of
+ * unwanted positive feedback control loops in which more threads
+ * cause more dependent stalls (as well as delayed progress of
+ * unblocked threads to the point that we know they are available)
+ * leading to more situations requiring more threads, and so
+ * on. This aspect of control can be seen as an (analytically
+ * intractable) game with an opponent that may choose the worst
+ * (for us) active thread to stall at any time. We take several
+ * precautions to bound losses (and thus bound gains), mainly in
+ * methods tryCompensate and awaitJoin.
*
* Common Pool
* ===========
@@ -579,52 +440,24 @@
* never be used, we minimize initial construction overhead and
* 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.
+ * fullExternalPush during the first submission to the pool.
*
* When external threads submit to the common pool, they can
- * perform subtask processing (see externalHelpComplete and
- * related methods) upon joins. This caller-helps policy makes it
- * sensible to set common pool parallelism level to one (or more)
- * less than the total number of available cores, or even zero for
- * pure caller-runs. We do not need to record whether external
- * submissions are to the common pool -- if not, external help
- * methods return quickly. These submitters would otherwise be
- * blocked waiting for completion, so the extra effort (with
- * liberally sprinkled task status checks) in inapplicable cases
- * amounts to an odd form of limited spin-wait before blocking in
- * ForkJoinTask.join.
- *
- * As a more appropriate default in managed environments, unless
- * overridden by system properties, we use workers of subclass
- * 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.runTask).
- * The associated mechanics (mainly in ForkJoinWorkerThread) may
- * be JVM-dependent and must access particular Thread class fields
- * to achieve this effect.
+ * perform subtask processing (see externalHelpJoin and related
+ * methods). This caller-helps policy makes it sensible to set
+ * common pool parallelism level to one (or more) less than the
+ * total number of available cores, or even zero for pure
+ * caller-runs. We do not need to record whether external
+ * submissions are to the common pool -- if not, externalHelpJoin
+ * returns quickly (at the most helping to signal some common pool
+ * workers). These submitters would otherwise be blocked waiting
+ * for completion, so the extra effort (with liberally sprinkled
+ * task status checks) in inapplicable cases amounts to an odd
+ * form of limited spin-wait before blocking in ForkJoinTask.join.
*
* Style notes
* ===========
*
- * 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. 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
* fields of WorkQueue maintain data structures managed by
@@ -632,13 +465,22 @@
* trying to reduce this, since any associated future changes in
* 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. There are also other coding oddities
- * (including several unnecessary-looking hoisted null checks)
- * that help some methods perform reasonably even when interpreted
- * (not compiled).
+ * they must accumulate sets of consistent reads of volatiles held
+ * in local variables. Methods signalWork() and scan() are the
+ * main bottlenecks, so are especially heavily
+ * micro-optimized/mangled. There are lots of inline assignments
+ * (of form "while ((local = field) != 0)") which are usually the
+ * simplest way to ensure the required read orderings (which are
+ * sometimes critical). This leads to a "C"-like style of listing
+ * declarations of these locals at the heads of methods or blocks.
+ * There are several occurrences of the unusual "do {} while
+ * (!cas...)" which is the simplest way to force an update of a
+ * CAS'ed variable. 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):
+ * The order of declarations in this file is:
* (1) Static utility functions
* (2) Nested (static) classes
* (3) Static fields
@@ -648,6 +490,7 @@
* (7) Exported methods
* (8) Static block initializing statics in minimally dependent order
*/
+ // android-note: Removed references to CountedCompleters.
// Static utilities
@@ -674,8 +517,7 @@
* Returns a new worker thread operating in the given pool.
*
* @param pool the pool this thread works in
- * @return the new worker thread, or {@code null} if the request
- * to create a thread is rejected
+ * @return the new worker thread
* @throws NullPointerException if the pool is null
*/
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
@@ -685,7 +527,7 @@
* Default ForkJoinWorkerThreadFactory implementation; creates a
* new ForkJoinWorkerThread.
*/
- private static final class DefaultForkJoinWorkerThreadFactory
+ static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new ForkJoinWorkerThread(pool);
@@ -698,7 +540,7 @@
* 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> {
+ 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; }
@@ -707,54 +549,54 @@
}
/**
- * 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 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.scanState and ctl sp subfield
- static final int UNSIGNALLED = 1 << 31; // must be negative
- static final int SS_SEQ = 1 << 16; // version count
-
- // 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
-
- /**
- * 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 POLL_LIMIT = (1 << 10) - 1;
-
- /**
* Queues supporting work-stealing as well as external task
- * submission. See above for descriptions and algorithms.
+ * submission. See above for main rationale and algorithms.
+ * Implementation relies heavily on "Unsafe" intrinsics
+ * and selective use of "volatile":
+ *
+ * Field "base" is the index (mod array.length) of the least valid
+ * queue slot, which is always the next position to steal (poll)
+ * from if nonempty. Reads and writes require volatile orderings
+ * but not CAS, because updates are only performed after slot
+ * CASes.
+ *
+ * Field "top" is the index (mod array.length) of the next queue
+ * slot to push to or pop from. It is written only by owner thread
+ * for push, or under lock for external/shared push, and accessed
+ * by other threads only after reading (volatile) base. Both top
+ * and base are allowed to wrap around on overflow, but (top -
+ * base) (or more commonly -(base - top) to force volatile read of
+ * base before top) still estimates size. The lock ("qlock") is
+ * forced to -1 on termination, causing all further lock attempts
+ * to fail. (Note: we don't need CAS for termination state because
+ * upon pool shutdown, all shared-queues will stop being used
+ * anyway.) Nearly all lock bodies are set up so that exceptions
+ * within lock bodies are "impossible" (modulo JVM errors that
+ * would cause failure anyway.)
+ *
+ * The array slots are read and written using the emulation of
+ * volatiles/atomics provided by Unsafe. Insertions must in
+ * general use putOrderedObject as a form of releasing store to
+ * ensure that all writes to the task object are ordered before
+ * its publication in the queue. All removals entail a CAS to
+ * null. The array is always a power of two. To ensure safety of
+ * Unsafe array operations, all accesses perform explicit null
+ * checks and implicit bounds checks via power-of-two masking.
+ *
+ * In addition to basic queuing support, this class contains
+ * fields described elsewhere to control execution. It turns out
+ * to work better memory-layout-wise to include them in this class
+ * rather than a separate class.
+ *
* 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.
+ * arrays sharing cache lines. (It would be best for queue objects
+ * and their arrays to share, but there is nothing available to
+ * help arrange that). The @Contended annotation alerts JVMs to
+ * try to keep instances apart.
*/
- //@jdk.internal.vm.annotation.Contended // android-removed
static final class WorkQueue {
-
/**
* Capacity of work-stealing queue array upon initialization.
* Must be a power of two; at least 4, but should be larger to
@@ -775,44 +617,43 @@
*/
static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
- // Instance fields
+ // Heuristic padding to ameliorate unfortunate memory placements
+ volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06;
- volatile int scanState; // versioned, negative if inactive
- int stackPred; // pool stack (ctl) predecessor
+ volatile int eventCount; // encoded inactivation count; < 0 if inactive
+ int nextWait; // encoded record of next event waiter
int nsteals; // number of steals
- int hint; // randomization and stealer index hint
- int config; // pool index and mode
- volatile int qlock; // 1: locked, < 0: terminate; else 0
+ int hint; // steal index hint
+ short poolIndex; // index of this queue in pool
+ final short mode; // 0: lifo, > 0: fifo, < 0: shared
+ volatile int qlock; // 1: locked, -1: 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
+ volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
+ ForkJoinTask<?> currentSteal; // current non-local task being executed
- // @jdk.internal.vm.annotation.Contended("group2") // segregate // android-removed
- volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
+ volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17;
+ volatile Object pad18, pad19, pad1a, pad1b, pad1c, pad1d;
- WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
+ WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode,
+ int seed) {
this.pool = pool;
this.owner = owner;
+ this.mode = (short)mode;
+ this.hint = seed; // store initial seed for runWorker
// Place indices in the center of array (that is not yet allocated)
base = top = INITIAL_QUEUE_CAPACITY >>> 1;
}
/**
- * Returns an exportable index (used by ForkJoinWorkerThread).
- */
- final int getPoolIndex() {
- return (config & 0xffff) >>> 1; // ignore odd/even tag bit
- }
-
- /**
* Returns the approximate number of tasks in the queue.
*/
final int queueSize() {
- int n = base - top; // read base first
+ int n = base - top; // non-owner callers must read base first
return (n >= 0) ? 0 : -n; // ignore transient negative
}
@@ -822,31 +663,32 @@
* near-empty queue has at least one unclaimed task.
*/
final boolean isEmpty() {
- ForkJoinTask<?>[] a; int n, al, s;
- return ((n = base - (s = top)) >= 0 || // possibly one task
- (n == -1 && ((a = array) == null ||
- (al = a.length) == 0 ||
- a[(al - 1) & (s - 1)] == null)));
+ ForkJoinTask<?>[] a; int m, s;
+ int n = base - (s = top);
+ return (n >= 0 ||
+ (n == -1 &&
+ ((a = array) == null ||
+ (m = a.length - 1) < 0 ||
+ U.getObject
+ (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null)));
}
/**
- * Pushes a task. Call only by owner in unshared queues.
+ * Pushes a task. Call only by owner in unshared queues. (The
+ * shared-queue version is embedded in method externalPush.)
*
* @param task the task. Caller must ensure non-null.
* @throws RejectedExecutionException if array cannot be resized
*/
final void push(ForkJoinTask<?> 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;
- ForkJoinPool p = pool;
- if ((d = base - s) == 0 && p != null) {
- U.fullFence();
- p.signalWork();
- }
- else if (al + d == 1)
+ ForkJoinTask<?>[] a; ForkJoinPool p;
+ int s = top, n;
+ if ((a = array) != null) { // ignore if queue removed
+ int m = a.length - 1;
+ U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
+ if ((n = (top = s + 1) - base) <= 2)
+ (p = pool).signalWork(p.workQueues, this);
+ else if (n >= m)
growArray();
}
}
@@ -859,23 +701,22 @@
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)
+ if (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 &&
+ 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);
+ do {
+ ForkJoinTask<?> x;
+ int oldj = ((b & oldMask) << ASHIFT) + ABASE;
+ int j = ((b & mask) << ASHIFT) + ABASE;
+ x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj);
if (x != null &&
- U.compareAndSwapObject(oldA, offset, x, null))
- a[b & mask] = x;
+ U.compareAndSwapObject(oldA, oldj, x, null))
+ U.putObjectVolatile(a, j, x);
} while (++b != t);
- U.storeFence();
}
return a;
}
@@ -885,16 +726,16 @@
* 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;
+ ForkJoinTask<?>[] a; ForkJoinTask<?> t; int m;
+ if ((a = array) != null && (m = a.length - 1) >= 0) {
+ for (int s; (s = top - 1) - base >= 0;) {
+ long j = ((m & s) << ASHIFT) + ABASE;
+ if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)
+ break;
+ if (U.compareAndSwapObject(a, j, t, null)) {
+ top = s;
+ return t;
+ }
}
}
return null;
@@ -903,18 +744,15 @@
/**
* 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.
+ * appear in ForkJoinPool methods scan and tryHelpStealer.
*/
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;
+ ForkJoinTask<?> t; ForkJoinTask<?>[] a;
+ if ((a = array) != null) {
+ int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) != null &&
+ base == b && U.compareAndSwapObject(a, j, t, null)) {
+ U.putOrderedInt(this, QBASE, b + 1);
return t;
}
}
@@ -925,27 +763,21 @@
* Takes next task, if one exists, in FIFO order.
*/
final ForkJoinTask<?> poll() {
- 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
+ ForkJoinTask<?>[] a; int b; ForkJoinTask<?> t;
+ while ((b = base) - top < 0 && (a = array) != null) {
+ int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ t = (ForkJoinTask<?>)U.getObjectVolatile(a, j);
+ if (t != null) {
+ if (U.compareAndSwapObject(a, j, t, null)) {
+ U.putOrderedInt(this, QBASE, b + 1);
+ return t;
}
}
- else
- break;
+ else if (base == b) {
+ if (b + 1 == top)
+ break;
+ Thread.yield(); // wait for lagging update (very rare)
+ }
}
return null;
}
@@ -954,350 +786,218 @@
* Takes next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> nextLocalTask() {
- return (config < 0) ? poll() : pop();
+ return mode == 0 ? pop() : poll();
}
/**
* Returns next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> peek() {
- int al; ForkJoinTask<?>[] a;
- return ((a = array) != null && (al = a.length) > 0) ?
- a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+ ForkJoinTask<?>[] a = array; int m;
+ if (a == null || (m = a.length - 1) < 0)
+ return null;
+ int i = mode == 0 ? top - 1 : base;
+ int j = ((i & m) << ASHIFT) + ABASE;
+ return (ForkJoinTask<?>)U.getObjectVolatile(a, j);
}
/**
* Pops the given task only if it is at the current top.
+ * (A shared version is available only via FJP.tryExternalUnpush)
*/
- final boolean tryUnpush(ForkJoinTask<?> task) {
- 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;
- }
+ final boolean tryUnpush(ForkJoinTask<?> t) {
+ ForkJoinTask<?>[] a; int s;
+ if ((a = array) != null && (s = top) != base &&
+ U.compareAndSwapObject
+ (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, 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 trySharedUnpush(ForkJoinTask<?> task) {
- boolean popped = false;
- 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;
- }
-
- /**
* Removes and cancels all known tasks, ignoring any exceptions.
*/
final void cancelAll() {
- 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(currentJoin);
+ ForkJoinTask.cancelIgnoringExceptions(currentSteal);
+ for (ForkJoinTask<?> t; (t = poll()) != null; )
ForkJoinTask.cancelIgnoringExceptions(t);
}
// Specialized execution methods
/**
- * Pops and executes up to POLL_LIMIT tasks or until empty.
+ * Polls and runs tasks until empty.
*/
- 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
- break;
- }
- else
- break;
- }
+ final void pollAndExecAll() {
+ for (ForkJoinTask<?> t; (t = poll()) != null;)
+ t.doExec();
}
/**
- * 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.
+ * Executes a top-level task and any local tasks remaining
+ * after execution.
*/
final void runTask(ForkJoinTask<?> task) {
- if (task != null) {
+ if ((currentSteal = task) != null) {
task.doExec();
- if (config < 0)
- localPollAndExec();
- else
- localPopAndExec();
- int ns = ++nsteals;
- ForkJoinWorkerThread thread = owner;
+ ForkJoinTask<?>[] a = array;
+ int md = mode;
+ ++nsteals;
currentSteal = null;
- if (ns < 0) // collect on overflow
- transferStealCount(pool);
- if (thread != null)
- thread.afterTopLevelExec();
- }
- }
-
- /**
- * Adds steal count to pool steal count if it exists, and resets.
- */
- 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();
+ if (md != 0)
+ pollAndExecAll();
+ else if (a != null) {
+ int s, m = a.length - 1;
+ while ((s = top - 1) - base >= 0) {
+ long i = ((m & s) << ASHIFT) + ABASE;
+ ForkJoinTask<?> t = (ForkJoinTask<?>)U.getObject(a, i);
+ if (t == null)
+ break;
+ if (U.compareAndSwapObject(a, i, t, null)) {
+ top = s;
+ t.doExec();
+ }
+ }
}
}
}
/**
* If present, removes from queue and executes the given task,
- * or any other cancelled task. Used only by awaitJoin.
+ * or any other cancelled task. Returns (true) on any CAS
+ * or consistency check failure so caller can retry.
*
- * @return true if queue empty and task not known to be done
+ * @return false if no progress can be made, else true
*/
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;
- }
- }
- 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;
- }
- break;
- }
- 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
+ boolean stat;
+ ForkJoinTask<?>[] a; int m, s, b, n;
+ if (task != null && (a = array) != null && (m = a.length - 1) >= 0 &&
+ (n = (s = top) - (b = base)) > 0) {
+ boolean removed = false, empty = true;
+ stat = true;
+ for (ForkJoinTask<?> t;;) { // traverse from s to b
+ long j = ((--s & m) << ASHIFT) + ABASE;
+ t = (ForkJoinTask<?>)U.getObject(a, j);
+ if (t == null) // inconsistent length
+ break;
+ else if (t == task) {
+ if (s + 1 == top) { // pop
+ if (!U.compareAndSwapObject(a, j, task, null))
break;
- return false;
+ top = s;
+ removed = true;
}
+ else if (base == b) // replace with proxy
+ removed = U.compareAndSwapObject(a, j, task,
+ new EmptyTask());
+ break;
}
- 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;
+ else if (t.status >= 0)
+ empty = false;
+ else if (s + 1 == top) { // pop and throw away
+ if (U.compareAndSwapObject(a, j, t, null))
+ top = s;
+ break;
+ }
+ if (--n == 0) {
+ if (!empty && base == b)
+ stat = false;
+ 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;
- }
- }
- }
+ if (removed)
+ task.doExec();
}
else
- h = b | Integer.MIN_VALUE; // to sense movement on re-poll
- return h;
+ stat = false;
+ return stat;
+ }
+
+ /**
+ * Tries to poll for and execute the given task or any other
+ * task in its CountedCompleter computation.
+ */
+ final boolean pollAndExecCC(CountedCompleter<?> root) {
+ ForkJoinTask<?>[] a; int b; Object o; CountedCompleter<?> t, r;
+ if ((b = base) - top < 0 && (a = array) != null) {
+ long j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ if ((o = U.getObjectVolatile(a, j)) == null)
+ return true; // retry
+ if (o instanceof CountedCompleter) {
+ for (t = (CountedCompleter<?>)o, r = t;;) {
+ if (r == root) {
+ if (base == b &&
+ U.compareAndSwapObject(a, j, t, null)) {
+ U.putOrderedInt(this, QBASE, b + 1);
+ t.doExec();
+ }
+ return true;
+ }
+ else if ((r = r.completer) == null)
+ break; // not part of root computation
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tries to pop and execute the given task or any other task
+ * in its CountedCompleter computation.
+ */
+ final boolean externalPopAndExecCC(CountedCompleter<?> root) {
+ ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r;
+ if (base - (s = top) < 0 && (a = array) != null) {
+ long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
+ if ((o = U.getObject(a, j)) instanceof CountedCompleter) {
+ for (t = (CountedCompleter<?>)o, r = t;;) {
+ if (r == root) {
+ if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+ if (top == s && array == a &&
+ U.compareAndSwapObject(a, j, t, null)) {
+ top = s - 1;
+ qlock = 0;
+ t.doExec();
+ }
+ else
+ qlock = 0;
+ }
+ return true;
+ }
+ else if ((r = r.completer) == null)
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Internal version
+ */
+ final boolean internalPopAndExecCC(CountedCompleter<?> root) {
+ ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r;
+ if (base - (s = top) < 0 && (a = array) != null) {
+ long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
+ if ((o = U.getObject(a, j)) instanceof CountedCompleter) {
+ for (t = (CountedCompleter<?>)o, r = t;;) {
+ if (r == root) {
+ if (U.compareAndSwapObject(a, j, t, null)) {
+ top = s - 1;
+ t.doExec();
+ }
+ return true;
+ }
+ else if ((r = r.completer) == null)
+ break;
+ }
+ }
+ }
+ return false;
}
/**
@@ -1305,28 +1005,34 @@
*/
final boolean isApparentlyUnblocked() {
Thread wt; Thread.State s;
- return (scanState >= 0 &&
+ return (eventCount >= 0 &&
(wt = owner) != null &&
(s = wt.getState()) != Thread.State.BLOCKED &&
s != Thread.State.WAITING &&
s != Thread.State.TIMED_WAITING);
}
- // 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();
+ // Unsafe mechanics
+ private static final sun.misc.Unsafe U;
+ private static final long QBASE;
private static final long QLOCK;
private static final int ABASE;
private static final int ASHIFT;
static {
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = WorkQueue.class;
+ Class<?> ak = ForkJoinTask[].class;
+ QBASE = U.objectFieldOffset
+ (k.getDeclaredField("base"));
QLOCK = U.objectFieldOffset
- (WorkQueue.class.getDeclaredField("qlock"));
- ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
- int scale = U.arrayIndexScale(ForkJoinTask[].class);
+ (k.getDeclaredField("qlock"));
+ ABASE = U.arrayBaseOffset(ak);
+ int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
+ throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (ReflectiveOperationException e) {
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -1335,6 +1041,15 @@
// static fields (initialized in static initializer below)
/**
+ * Per-thread submission bookkeeping. Shared across all pools
+ * to reduce ThreadLocal pollution and because random motion
+ * to avoid contention in one pool is likely to hold for others.
+ * Lazily initialized on first submission (but null-checked
+ * in other contexts to avoid unnecessary initialization).
+ */
+ static final ThreadLocal<Submitter> submitters;
+
+ /**
* Creates a new ForkJoinWorkerThread. This factory is used unless
* overridden in ForkJoinPool constructors.
*/
@@ -1343,9 +1058,9 @@
/**
* Permission required for callers of methods that may start or
- * kill threads. Also used as a static lock in tryInitialize.
+ * kill threads.
*/
- static final RuntimePermission modifyThreadPermission;
+ private static final RuntimePermission modifyThreadPermission;
/**
* Common (static) pool. Non-null for public use unless a static
@@ -1361,12 +1076,7 @@
* common.parallelism field to be zero, but in that case still report
* parallelism as 1 to reflect resulting caller-runs mechanics.
*/
- static final int COMMON_PARALLELISM;
-
- /**
- * Limit on spare thread construction in tryCompensate.
- */
- private static final int COMMON_MAX_SPARES;
+ static final int commonParallelism;
/**
* Sequence number for creating workerNamePrefix.
@@ -1381,215 +1091,270 @@
return ++poolNumberSequence;
}
- // static configuration constants
+ // static constants
/**
- * Initial timeout value (in milliseconds) for the thread
+ * Initial timeout value (in nanoseconds) 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).
+ * 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 IDLE_TIMEOUT_MS = 2000L; // 2sec
+ private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
/**
- * Tolerance for idle timeouts, to cope with timer undershoots.
+ * Timeout value when there are more threads than parallelism level
*/
- private static final long TIMEOUT_SLOP_MS = 20L; // 20ms
+ private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L;
/**
- * The default value for COMMON_MAX_SPARES. Overridable using the
- * "java.util.concurrent.ForkJoinPool.common.maximumSpares" system
- * property. The default value is far in excess of normal
- * requirements, but also far short of MAX_CAP and typical OS
- * thread limits, so allows JVMs to catch misuse/abuse before
- * running out of resources needed to do so.
+ * Tolerance for idle timeouts, to cope with timer undershoots
*/
- private static final int DEFAULT_COMMON_MAX_SPARES = 256;
+ private static final long TIMEOUT_SLOP = 2000000L;
+
+ /**
+ * The maximum stolen->joining link depth allowed in method
+ * tryHelpStealer. Must be a power of two. Depths for legitimate
+ * chains are unbounded, but we use a fixed constant to avoid
+ * (otherwise unchecked) cycles and to bound staleness of
+ * traversal parameters at the expense of sometimes blocking when
+ * we could be helping.
+ */
+ private static final int MAX_HELP = 64;
/**
* Increment for seed generators. See class ThreadLocal for
* explanation.
*/
- private static final int SEED_INCREMENT = 0x9e3779b9;
+ private static final int SEED_INCREMENT = 0x61c88647;
/*
- * Bits and masks for field ctl, packed with 4 16 bit subfields:
- * 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
+ * Bits and masks for control variables
*
- * When convenient, we can extract the lower 32 stack top bits
- * (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 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.
+ * Field ctl is a long packed with:
+ * AC: Number of active running workers minus target parallelism (16 bits)
+ * TC: Number of total workers minus target parallelism (16 bits)
+ * ST: true if pool is terminating (1 bit)
+ * EC: the wait count of top waiting thread (15 bits)
+ * ID: poolIndex of top of Treiber stack of waiters (16 bits)
*
- * 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.
+ * When convenient, we can extract the upper 32 bits of counts and
+ * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e =
+ * (int)ctl. The ec field is never accessed alone, but always
+ * together with id and st. 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 active workers, when tc is
+ * negative, there are not enough total workers, and when e is
+ * negative, the pool is terminating. To deal with these possibly
+ * negative fields, we use casts in and out of "short" and/or
+ * signed shifts to maintain signedness.
+ *
+ * When a thread is queued (inactivated), its eventCount field is
+ * set negative, which is the only way to tell if a worker is
+ * prevented from executing tasks, even though it must continue to
+ * scan for them to avoid queuing races. Note however that
+ * eventCount updates lag releases so usage requires care.
+ *
+ * Field plock is an int packed with:
+ * SHUTDOWN: true if shutdown is enabled (1 bit)
+ * SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits)
+ * SIGNAL: set when threads may be waiting on the lock (1 bit)
+ *
+ * The sequence number enables simple consistency checks:
+ * Staleness of read-only operations on the workQueues array can
+ * be checked by comparing plock before vs after the reads.
*/
- // Lower and upper word masks
- private static final long SP_MASK = 0xffffffffL;
- private static final long UC_MASK = ~SP_MASK;
-
- // Active counts
+ // bit positions/shifts for fields
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;
- private static final long TC_UNIT = 0x0001L << TC_SHIFT;
- private static final long TC_MASK = 0xffffL << TC_SHIFT;
- private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
+ private static final int ST_SHIFT = 31;
+ private static final int EC_SHIFT = 16;
- // 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;
+ // bounds
+ private static final int SMASK = 0xffff; // short bits
+ private static final int MAX_CAP = 0x7fff; // max #workers - 1
+ private static final int EVENMASK = 0xfffe; // even short bits
+ private static final int SQMASK = 0x007e; // max 64 (even) slots
+ private static final int SHORT_SIGN = 1 << 15;
+ private static final int INT_SIGN = 1 << 31;
+
+ // masks
+ private static final long STOP_BIT = 0x0001L << ST_SHIFT;
+ private static final long AC_MASK = ((long)SMASK) << AC_SHIFT;
+ private static final long TC_MASK = ((long)SMASK) << TC_SHIFT;
+
+ // units for incrementing and decrementing
+ private static final long TC_UNIT = 1L << TC_SHIFT;
+ private static final long AC_UNIT = 1L << AC_SHIFT;
+
+ // masks and units for dealing with u = (int)(ctl >>> 32)
+ private static final int UAC_SHIFT = AC_SHIFT - 32;
+ private static final int UTC_SHIFT = TC_SHIFT - 32;
+ private static final int UAC_MASK = SMASK << UAC_SHIFT;
+ private static final int UTC_MASK = SMASK << UTC_SHIFT;
+ private static final int UAC_UNIT = 1 << UAC_SHIFT;
+ private static final int UTC_UNIT = 1 << UTC_SHIFT;
+
+ // masks and units for dealing with e = (int)ctl
+ private static final int E_MASK = 0x7fffffff; // no STOP_BIT
+ private static final int E_SEQ = 1 << EC_SHIFT;
+
+ // plock bits
+ private static final int SHUTDOWN = 1 << 31;
+ private static final int PL_LOCK = 2;
+ private static final int PL_SIGNAL = 1;
+ private static final int PL_SPINS = 1 << 8;
+
+ // access mode for WorkQueue
+ static final int LIFO_QUEUE = 0;
+ static final int FIFO_QUEUE = 1;
+ static final int SHARED_QUEUE = -1;
+
+ // Heuristic padding to ameliorate unfortunate memory placements
+ volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06;
// 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
+ volatile long stealCount; // collects worker counts
+ volatile long ctl; // main pool control
+ volatile int plock; // shutdown status and seqLock
+ volatile int indexSeed; // worker/submitter index seed
+ final short parallelism; // parallelism level
+ final short mode; // LIFO/FIFO
+ WorkQueue[] workQueues; // main registry
final ForkJoinWorkerThreadFactory factory;
- final UncaughtExceptionHandler ueh; // per-worker UEH
+ final UncaughtExceptionHandler ueh; // per-worker UEH
+ final String workerNamePrefix; // to create worker name string
+
+ volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17;
+ volatile Object pad18, pad19, pad1a, pad1b;
/**
- * Instantiates fields upon first submission, or upon shutdown if
- * no submissions. If checkTermination true, also responds to
- * termination by external calls submitting tasks.
+ * Acquires the plock lock to protect worker array and related
+ * updates. This method is called only if an initial CAS on plock
+ * fails. This acts as a spinlock for normal cases, but falls back
+ * to builtin monitor to block when (rarely) needed. This would be
+ * a terrible idea for a highly contended lock, but works fine as
+ * a more conservative alternative to a pure spinlock.
*/
- 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;
+ private int acquirePlock() {
+ int spins = PL_SPINS, ps, nps;
+ for (;;) {
+ if (((ps = plock) & PL_LOCK) == 0 &&
+ U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK))
+ return nps;
+ else if (spins >= 0) {
+ if (ThreadLocalRandom.current().nextInt() >= 0)
+ --spins;
+ }
+ else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) {
+ synchronized (this) {
+ if ((plock & PL_SIGNAL) != 0) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ try {
+ Thread.currentThread().interrupt();
+ } catch (SecurityException ignore) {
+ }
+ }
+ }
+ else
+ notifyAll();
}
}
}
- if (checkTermination && runState < 0) {
- tryTerminate(false, false); // help terminate
- throw new RejectedExecutionException();
- }
- }
-
- // Creating, registering and deregistering workers
-
- /**
- * Tries to construct and start one worker. Assumes that total
- * 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(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;
- }
- } catch (Throwable rex) {
- ex = rex;
- }
- deregisterWorker(wt, ex);
- return false;
}
/**
- * Tries to add one worker, incrementing ctl counts before doing
- * so, relying on createWorker to back out on failure.
- *
- * @param c incoming ctl value, with total count negative and no
- * idle workers. On CAS failure, c is refreshed and retried if
- * this holds (otherwise, a new worker is not needed).
+ * Unlocks and signals any thread waiting for plock. Called only
+ * when CAS of seq value for unlock fails.
*/
- private void tryAddWorker(long c) {
- do {
- long nc = ((AC_MASK & (c + AC_UNIT)) |
- (TC_MASK & (c + TC_UNIT)));
- if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
- createWorker(false);
+ private void releasePlock(int ps) {
+ plock = ps;
+ synchronized (this) { notifyAll(); }
+ }
+
+ /**
+ * Tries to create and start one worker if fewer than target
+ * parallelism level exist. Adjusts counts etc on failure.
+ */
+ private void tryAddWorker() {
+ long c; int u, e;
+ while ((u = (int)((c = ctl) >>> 32)) < 0 &&
+ (u & SHORT_SIGN) != 0 && (e = (int)c) >= 0) {
+ long nc = ((long)(((u + UTC_UNIT) & UTC_MASK) |
+ ((u + UAC_UNIT) & UAC_MASK)) << 32) | (long)e;
+ if (U.compareAndSwapLong(this, CTL, c, nc)) {
+ ForkJoinWorkerThreadFactory fac;
+ Throwable ex = null;
+ ForkJoinWorkerThread wt = null;
+ try {
+ if ((fac = factory) != null &&
+ (wt = fac.newThread(this)) != null) {
+ wt.start();
+ break;
+ }
+ } catch (Throwable rex) {
+ ex = rex;
+ }
+ deregisterWorker(wt, ex);
break;
}
- } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
+ }
}
+ // Registering and deregistering workers
+
/**
- * Callback from ForkJoinWorkerThread constructor to establish and
- * record its WorkQueue.
+ * Callback from ForkJoinWorkerThread to establish and record its
+ * WorkQueue. To avoid scanning bias due to packing entries in
+ * front of the workQueues array, we treat the array as a simple
+ * power-of-two hash table using per-thread seed as hash,
+ * expanding as needed.
*
* @param wt the worker thread
* @return the worker's queue
*/
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
- UncaughtExceptionHandler handler;
- AuxState aux;
- wt.setDaemon(true); // configure thread
+ UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps;
+ wt.setDaemon(true);
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
- WorkQueue w = new WorkQueue(this, wt);
- 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;
- }
+ do {} while (!U.compareAndSwapInt(this, INDEXSEED, s = indexSeed,
+ s += SEED_INCREMENT) ||
+ s == 0); // skip 0
+ WorkQueue w = new WorkQueue(this, wt, mode, s);
+ if (((ps = plock) & PL_LOCK) != 0 ||
+ !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+ ps = acquirePlock();
+ int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+ try {
+ if ((ws = workQueues) != null) { // skip if shutting down
+ int n = ws.length, m = n - 1;
+ int r = (s << 1) | 1; // use odd-numbered indices
+ if (ws[r &= m] != null) { // collision
+ int probes = 0; // step by approx half size
+ int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
+ while (ws[r = (r + step) & m] != null) {
+ if (++probes >= n) {
+ workQueues = ws = Arrays.copyOf(ws, n <<= 1);
+ m = n - 1;
+ probes = 0;
}
}
- 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();
+ w.poolIndex = (short)r;
+ w.eventCount = r; // volatile write orders
+ ws[r] = w;
}
+ } finally {
+ if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+ releasePlock(nps);
}
- wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
+ wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex >>> 1)));
return w;
}
@@ -1605,628 +1370,672 @@
final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
WorkQueue w = null;
if (wt != null && (w = wt.workQueue) != null) {
- 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();
+ int ps; long sc;
+ w.qlock = -1; // ensure set
+ do {} while (!U.compareAndSwapLong(this, STEALCOUNT,
+ sc = stealCount,
+ sc + w.nsteals));
+ if (((ps = plock) & PL_LOCK) != 0 ||
+ !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+ ps = acquirePlock();
+ int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+ try {
+ int idx = w.poolIndex;
+ WorkQueue[] ws = workQueues;
+ if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w)
+ ws[idx] = null;
+ } finally {
+ if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+ releasePlock(nps);
+ }
+ }
+
+ long c; // adjust ctl counts
+ do {} while (!U.compareAndSwapLong
+ (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) |
+ ((c - TC_UNIT) & TC_MASK) |
+ (c & ~(AC_MASK|TC_MASK)))));
+
+ if (!tryTerminate(false, false) && w != null && w.array != null) {
+ w.cancelAll(); // cancel remaining tasks
+ WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e;
+ while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) {
+ if (e > 0) { // activate or create replacement
+ if ((ws = workQueues) == null ||
+ (i = e & SMASK) >= ws.length ||
+ (v = ws[i]) == null)
+ break;
+ long nc = (((long)(v.nextWait & E_MASK)) |
+ ((long)(u + UAC_UNIT) << 32));
+ if (v.eventCount != (e | INT_SIGN))
+ break;
+ if (U.compareAndSwapLong(this, CTL, c, nc)) {
+ v.eventCount = (e + E_SEQ) & E_MASK;
+ if ((p = v.parker) != null)
+ U.unpark(p);
+ break;
+ }
+ }
+ else {
+ if ((short)u < 0)
+ tryAddWorker();
+ break;
}
}
}
- if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
- long c; // decrement counts
- do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
- (TC_MASK & (c - TC_UNIT)) |
- (SP_MASK & c))));
- }
- if (w != null) {
- w.currentSteal = null;
- w.qlock = -1; // ensure set
- w.cancelAll(); // cancel remaining tasks
- }
- 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
+ if (ex == null) // help clean refs on way out
ForkJoinTask.helpExpungeStaleExceptions();
- else // rethrow
+ else // rethrow
ForkJoinTask.rethrow(ex);
}
- // Signalling
+ // Submissions
+
+ /**
+ * Per-thread records for threads that submit to pools. Currently
+ * holds only pseudo-random seed / index that is used to choose
+ * submission queues in method externalPush. In the future, this may
+ * also incorporate a means to implement different task rejection
+ * and resubmission policies.
+ *
+ * Seeds for submitters and workers/workQueues work in basically
+ * the same way but are initialized and updated using slightly
+ * different mechanics. Both are initialized using the same
+ * approach as in class ThreadLocal, where successive values are
+ * unlikely to collide with previous values. Seeds are then
+ * randomly modified upon collisions using xorshifts, which
+ * requires a non-zero seed.
+ */
+ static final class Submitter {
+ int seed;
+ Submitter(int s) { seed = s; }
+ }
+
+ /**
+ * Unless shutting down, adds the given task to a submission queue
+ * at submitter's current queue index (modulo submission
+ * range). Only the most common path is directly handled in this
+ * method. All others are relayed to fullExternalPush.
+ *
+ * @param task the task. Caller must ensure non-null.
+ */
+ final void externalPush(ForkJoinTask<?> task) {
+ Submitter z = submitters.get();
+ WorkQueue q; int r, m, s, n, am; ForkJoinTask<?>[] a;
+ int ps = plock;
+ WorkQueue[] ws = workQueues;
+ if (z != null && ps > 0 && ws != null && (m = (ws.length - 1)) >= 0 &&
+ (q = ws[m & (r = z.seed) & SQMASK]) != null && r != 0 &&
+ U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock
+ if ((a = q.array) != null &&
+ (am = a.length - 1) > (n = (s = q.top) - q.base)) {
+ int j = ((am & s) << ASHIFT) + ABASE;
+ U.putOrderedObject(a, j, task);
+ q.top = s + 1; // push on to deque
+ q.qlock = 0;
+ if (n <= 1)
+ signalWork(ws, q);
+ return;
+ }
+ q.qlock = 0;
+ }
+ fullExternalPush(task);
+ }
+
+ /**
+ * Full version of externalPush. This method is called, among
+ * other times, upon the first submission of the first task to the
+ * pool, so must perform secondary initialization. It also
+ * detects first submission by an external thread by looking up
+ * its ThreadLocal, and creates a new shared queue if the one at
+ * index if empty or contended. The plock lock body must be
+ * exception-free (so no try/finally) so we optimistically
+ * allocate new queues outside the lock and throw them away if
+ * (very rarely) not needed.
+ *
+ * Secondary initialization occurs when plock is zero, to create
+ * workQueue array and set plock to a valid value. This lock body
+ * must also be exception-free. Because the plock seq value can
+ * eventually wrap around zero, this method harmlessly fails to
+ * reinitialize if workQueues exists, while still advancing plock.
+ */
+ private void fullExternalPush(ForkJoinTask<?> task) {
+ int r = 0; // random index seed
+ for (Submitter z = submitters.get();;) {
+ WorkQueue[] ws; WorkQueue q; int ps, m, k;
+ if (z == null) {
+ if (U.compareAndSwapInt(this, INDEXSEED, r = indexSeed,
+ r += SEED_INCREMENT) && r != 0)
+ submitters.set(z = new Submitter(r));
+ }
+ else if (r == 0) { // move to a different index
+ r = z.seed;
+ r ^= r << 13; // same xorshift as WorkQueues
+ r ^= r >>> 17;
+ z.seed = r ^= (r << 5);
+ }
+ if ((ps = plock) < 0)
+ throw new RejectedExecutionException();
+ else if (ps == 0 || (ws = workQueues) == null ||
+ (m = ws.length - 1) < 0) { // initialize workQueues
+ int p = parallelism; // find power of two table size
+ int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
+ n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
+ n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
+ WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ?
+ new WorkQueue[n] : null);
+ if (((ps = plock) & PL_LOCK) != 0 ||
+ !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+ ps = acquirePlock();
+ if (((ws = workQueues) == null || ws.length == 0) && nws != null)
+ workQueues = nws;
+ int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+ if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+ releasePlock(nps);
+ }
+ else if ((q = ws[k = r & m & SQMASK]) != null) {
+ if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+ ForkJoinTask<?>[] a = q.array;
+ int s = q.top;
+ boolean submitted = false;
+ try { // locked version of push
+ if ((a != null && a.length > s + 1 - q.base) ||
+ (a = q.growArray()) != null) { // must presize
+ int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
+ U.putOrderedObject(a, j, task);
+ q.top = s + 1;
+ submitted = true;
+ }
+ } finally {
+ q.qlock = 0; // unlock
+ }
+ if (submitted) {
+ signalWork(ws, q);
+ return;
+ }
+ }
+ r = 0; // move on failure
+ }
+ else if (((ps = plock) & PL_LOCK) == 0) { // create new queue
+ q = new WorkQueue(this, null, SHARED_QUEUE, r);
+ q.poolIndex = (short)k;
+ if (((ps = plock) & PL_LOCK) != 0 ||
+ !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+ ps = acquirePlock();
+ if ((ws = workQueues) != null && k < ws.length && ws[k] == null)
+ ws[k] = q;
+ int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+ if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+ releasePlock(nps);
+ }
+ else
+ r = 0;
+ }
+ }
+
+ // Maintaining ctl counts
+
+ /**
+ * Increments active count; mainly called upon return from blocking.
+ */
+ final void incrementActiveCount() {
+ long c;
+ do {} while (!U.compareAndSwapLong
+ (this, CTL, c = ctl, ((c & ~AC_MASK) |
+ ((c & AC_MASK) + AC_UNIT))));
+ }
/**
* Tries to create or activate a worker if too few are active.
+ *
+ * @param ws the worker array to use to find signallees
+ * @param q if non-null, the queue holding tasks to be processed
*/
- final void signalWork() {
+ final void signalWork(WorkQueue[] ws, WorkQueue q) {
for (;;) {
- long c; int sp, i; WorkQueue v; WorkQueue[] ws;
- if ((c = ctl) >= 0L) // enough workers
+ long c; int e, u, i; WorkQueue w; Thread p;
+ if ((u = (int)((c = ctl) >>> 32)) >= 0)
break;
- else if ((sp = (int)c) == 0) { // no idle workers
- if ((c & ADD_WORKER) != 0L) // too few workers
- tryAddWorker(c);
+ if ((e = (int)c) <= 0) {
+ if ((short)u < 0)
+ tryAddWorker();
break;
}
- else if ((ws = workQueues) == null)
- break; // unstarted/terminated
- else if (ws.length <= (i = sp & SMASK))
- break; // terminated
- else if ((v = ws[i]) == null)
- break; // terminating
- else {
- 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;
- }
- }
- }
- }
-
- /**
- * 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.
- *
- * @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 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 &&
+ if (ws == null || ws.length <= (i = e & SMASK) ||
+ (w = ws[i]) == null)
+ break;
+ long nc = (((long)(w.nextWait & E_MASK)) |
+ ((long)(u + UAC_UNIT)) << 32);
+ int ne = (e + E_SEQ) & E_MASK;
+ if (w.eventCount == (e | INT_SIGN) &&
U.compareAndSwapLong(this, CTL, c, nc)) {
- v.scanState = ns;
- LockSupport.unpark(v.parker);
+ w.eventCount = ne;
+ if ((p = w.parker) != null)
+ U.unpark(p);
+ break;
}
- }
- }
-
- /**
- * 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;
- }
+ if (q != null && q.base >= q.top)
+ 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.
+ * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+ */
+ final void runWorker(WorkQueue w) {
+ w.growArray(); // allocate queue
+ for (int r = w.hint; scan(w, r) == 0; ) {
+ r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+ }
+ }
+
+ /**
+ * Scans for and, if found, runs one task, else possibly
+ * inactivates the worker. This method operates on single reads of
+ * volatile state and is designed to be re-invoked continuously,
+ * in part because it returns upon detecting inconsistencies,
+ * contention, or state changes that indicate possible success on
+ * re-invocation.
+ *
+ * The scan searches for tasks across queues starting at a random
+ * index, checking each at least twice. The scan terminates upon
+ * either finding a non-empty queue, or completing the sweep. If
+ * the worker is not inactivated, it takes and runs a task from
+ * this queue. Otherwise, if not activated, it tries to activate
+ * itself or some other worker by signalling. On failure to find a
+ * task, returns (for retry) if pool state may have changed during
+ * an empty scan, or tries to inactivate if active, else possibly
+ * blocks or terminates via method awaitWork.
*
* @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
+ * @param r a random seed
+ * @return worker qlock status if would have waited, else 0
*/
- 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
+ private final int scan(WorkQueue w, int r) {
+ WorkQueue[] ws; int m;
+ long c = ctl; // for consistency check
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && w != null) {
+ for (int j = m + m + 1, ec = w.eventCount;;) {
+ WorkQueue q; int b, e; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+ if ((q = ws[(r - j) & m]) != null &&
+ (b = q.base) - q.top < 0 && (a = q.array) != null) {
+ long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ if ((t = ((ForkJoinTask<?>)
+ U.getObjectVolatile(a, i))) != null) {
+ if (ec < 0)
+ helpRelease(c, ws, w, q, b);
+ else if (q.base == b &&
+ U.compareAndSwapObject(a, i, t, null)) {
+ U.putOrderedInt(q, QBASE, b + 1);
+ if ((b + 1) - q.top < 0)
+ signalWork(ws, q);
+ w.runTask(t);
+ }
}
- 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 (--j < 0) {
+ if ((ec | (e = (int)c)) < 0) // inactive or terminating
+ return awaitWork(w, c, ec);
+ else if (ctl == c) { // try to inactivate and enqueue
+ long nc = (long)ec | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
+ w.nextWait = e;
+ w.eventCount = ec | INT_SIGN;
+ if (!U.compareAndSwapLong(this, CTL, c, nc))
+ w.eventCount = ec; // back out
}
- else if (r >= 0) {
- inactivate(w, ss);
- break;
- }
- else
- r <<= 1; // at most 31 rescans
+ break;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * A continuation of scan(), possibly blocking or terminating
+ * worker w. Returns without blocking if pool state has apparently
+ * changed since last invocation. Also, if inactivating w has
+ * caused the pool to become quiescent, checks for pool
+ * termination, and, so long as this is not the only worker, waits
+ * for event for up to a given duration. 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
+ * @param c the ctl value on entry to scan
+ * @param ec the worker's eventCount on entry to scan
+ */
+ private final int awaitWork(WorkQueue w, long c, int ec) {
+ int stat, ns; long parkTime, deadline;
+ if ((stat = w.qlock) >= 0 && w.eventCount == ec && ctl == c &&
+ !Thread.interrupted()) {
+ int e = (int)c;
+ int u = (int)(c >>> 32);
+ int d = (u >> UAC_SHIFT) + parallelism; // active count
+
+ if (e < 0 || (d <= 0 && tryTerminate(false, false)))
+ stat = w.qlock = -1; // pool is terminating
+ else if ((ns = w.nsteals) != 0) { // collect steals and retry
+ long sc;
+ w.nsteals = 0;
+ do {} while (!U.compareAndSwapLong(this, STEALCOUNT,
+ sc = stealCount, sc + ns));
+ }
+ else {
+ long pc = ((d > 0 || ec != (e | INT_SIGN)) ? 0L :
+ ((long)(w.nextWait & E_MASK)) | // ctl to restore
+ ((long)(u + UAC_UNIT)) << 32);
+ if (pc != 0L) { // timed wait if last waiter
+ int dc = -(short)(c >>> TC_SHIFT);
+ parkTime = (dc < 0 ? FAST_IDLE_TIMEOUT:
+ (dc + 1) * IDLE_TIMEOUT);
+ deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP;
+ }
+ else
+ parkTime = deadline = 0L;
+ if (w.eventCount == ec && ctl == c) {
+ Thread wt = Thread.currentThread();
+ U.putObject(wt, PARKBLOCKER, this);
+ w.parker = wt; // emulate LockSupport.park
+ if (w.eventCount == ec && ctl == c)
+ U.park(false, parkTime); // must recheck before park
+ w.parker = null;
+ U.putObject(wt, PARKBLOCKER, null);
+ if (parkTime != 0L && ctl == c &&
+ deadline - System.nanoTime() <= 0L &&
+ U.compareAndSwapLong(this, CTL, c, pc))
+ stat = w.qlock = -1; // shrink pool
}
}
}
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
+ * Possibly releases (signals) a worker. Called only from scan()
+ * when a worker with apparently inactive status finds a non-empty
+ * queue. This requires revalidating all of the associated state
+ * from caller.
*/
- 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;
- }
- }
+ private final void helpRelease(long c, WorkQueue[] ws, WorkQueue w,
+ WorkQueue q, int b) {
+ WorkQueue v; int e, i; Thread p;
+ if (w != null && w.eventCount < 0 && (e = (int)c) > 0 &&
+ ws != null && ws.length > (i = e & SMASK) &&
+ (v = ws[i]) != null && ctl == c) {
+ long nc = (((long)(v.nextWait & E_MASK)) |
+ ((long)((int)(c >>> 32) + UAC_UNIT)) << 32);
+ int ne = (e + E_SEQ) & E_MASK;
+ if (q != null && q.base == b && w.eventCount < 0 &&
+ v.eventCount == (e | INT_SIGN) &&
+ U.compareAndSwapLong(this, CTL, c, nc)) {
+ v.eventCount = ne;
+ if ((p = v.parker) != null)
+ U.unpark(p);
}
}
- return s;
}
/**
* Tries to locate and execute tasks for a stealer of the given
- * task, or in turn one of its stealers. Traces currentSteal ->
+ * 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.
+ * leaves hints in workers to speed up subsequent calls. The
+ * implementation is very branchy to cope with potential
+ * inconsistencies or loops encountering chains that are stale,
+ * unknown, or so long that they are likely cyclic.
*
- * @param w caller
+ * @param joiner the joining worker
* @param task the task to join
+ * @return 0 if no progress can be made, negative if task
+ * known complete, else positive
*/
- 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;
+ private int tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) {
+ int stat = 0, steps = 0; // bound to avoid cycles
+ if (task != null && joiner != null &&
+ joiner.base - joiner.top >= 0) { // hoist checks
+ restart: for (;;) {
+ ForkJoinTask<?> subtask = task; // current target
+ for (WorkQueue j = joiner, v;;) { // v is stealer of subtask
+ WorkQueue[] ws; int m, s, h;
+ if ((s = task.status) < 0) {
+ stat = s;
+ break restart;
+ }
+ if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
+ break restart; // shutting down
+ if ((v = ws[h = (j.hint | 1) & m]) == null ||
+ v.currentSteal != subtask) {
+ for (int origin = h;;) { // find stealer
+ if (((h = (h + 2) & m) & 15) == 1 &&
+ (subtask.status < 0 || j.currentJoin != subtask))
+ continue restart; // occasional staleness check
+ if ((v = ws[h]) != null &&
+ v.currentSteal == subtask) {
+ j.hint = h; // save hint
break;
}
- checkSum += v.base;
+ if (h == origin)
+ break restart; // cannot find stealer
}
- 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;
- }
+ for (;;) { // help stealer or descend to its stealer
+ ForkJoinTask[] a; int b;
+ if (subtask.status < 0) // surround probes with
+ continue restart; // consistency checks
+ if ((b = v.base) - v.top < 0 && (a = v.array) != null) {
+ int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ ForkJoinTask<?> t =
+ (ForkJoinTask<?>)U.getObjectVolatile(a, i);
+ if (subtask.status < 0 || j.currentJoin != subtask ||
+ v.currentSteal != subtask)
+ continue restart; // stale
+ stat = 1; // apparent progress
+ if (v.base == b) {
+ if (t == null)
+ break restart;
+ if (U.compareAndSwapObject(a, i, t, null)) {
+ U.putOrderedInt(v, QBASE, b + 1);
+ ForkJoinTask<?> ps = joiner.currentSteal;
+ int jt = joiner.top;
+ do {
+ joiner.currentSteal = t;
+ t.doExec(); // clear local tasks too
+ } while (task.status >= 0 &&
+ joiner.top != jt &&
+ (t = joiner.pop()) != null);
+ joiner.currentSteal = ps;
+ break restart;
}
}
}
- 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;
+ else { // empty -- try to descend
+ ForkJoinTask<?> next = v.currentJoin;
+ if (subtask.status < 0 || j.currentJoin != subtask ||
+ v.currentSteal != subtask)
+ continue restart; // stale
+ else if (next == null || ++steps == MAX_HELP)
+ break restart; // dead-end or maybe cyclic
+ else {
+ subtask = next;
+ j = v;
+ break;
}
- j = v;
- break;
}
}
}
}
}
+ return stat;
}
/**
- * 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.
+ * Analog of tryHelpStealer for CountedCompleters. Tries to steal
+ * and run tasks within the target's computation.
*
- * @param w caller
+ * @param task the task to join
*/
- 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.
- *
- * @param w caller
- * @param task the task
- * @param deadline for timed waits, if nonzero
- * @return task status on exit
- */
- final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
+ private int helpComplete(WorkQueue joiner, CountedCompleter<?> task) {
+ WorkQueue[] ws; int m;
int s = 0;
- 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)
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
+ joiner != null && task != null) {
+ int j = joiner.poolIndex;
+ int scans = m + m + 1;
+ long c = 0L; // for stability check
+ for (int k = scans; ; j += 2) {
+ WorkQueue q;
+ if ((s = task.status) < 0)
+ break;
+ else if (joiner.internalPopAndExecCC(task))
+ k = scans;
+ else if ((s = task.status) < 0)
+ break;
+ else if ((q = ws[j & m]) != null && q.pollAndExecCC(task))
+ k = scans;
+ else if (--k < 0) {
+ if (c == (c = ctl))
break;
- long ms, ns;
- if (deadline == 0L)
- ms = 0L;
- else if ((ns = deadline - System.nanoTime()) <= 0L)
- break;
- else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
- ms = 1L;
- if (tryCompensate(w)) {
- task.internalWait(ms);
- U.getAndAddLong(this, CTL, AC_UNIT);
- }
- if ((s = task.status) < 0)
- break;
+ k = scans;
}
- w.currentJoin = prevJoin;
}
}
return s;
}
- // Specialized scanning
+ /**
+ * Tries to decrement active count (sometimes implicitly) and
+ * possibly release or create a compensating worker in preparation
+ * for blocking. Fails on contention or termination. Otherwise,
+ * adds a new thread if no idle workers are available and pool
+ * may become starved.
+ *
+ * @param c the assumed ctl value
+ */
+ final boolean tryCompensate(long c) {
+ WorkQueue[] ws = workQueues;
+ int pc = parallelism, e = (int)c, m, tc;
+ if (ws != null && (m = ws.length - 1) >= 0 && e >= 0 && ctl == c) {
+ WorkQueue w = ws[e & m];
+ if (e != 0 && w != null) {
+ Thread p;
+ long nc = ((long)(w.nextWait & E_MASK) |
+ (c & (AC_MASK|TC_MASK)));
+ int ne = (e + E_SEQ) & E_MASK;
+ if (w.eventCount == (e | INT_SIGN) &&
+ U.compareAndSwapLong(this, CTL, c, nc)) {
+ w.eventCount = ne;
+ if ((p = w.parker) != null)
+ U.unpark(p);
+ return true; // replace with idle worker
+ }
+ }
+ else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 &&
+ (int)(c >> AC_SHIFT) + pc > 1) {
+ long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
+ if (U.compareAndSwapLong(this, CTL, c, nc))
+ return true; // no compensation
+ }
+ else if (tc + pc < MAX_CAP) {
+ long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
+ if (U.compareAndSwapLong(this, CTL, c, nc)) {
+ ForkJoinWorkerThreadFactory fac;
+ Throwable ex = null;
+ ForkJoinWorkerThread wt = null;
+ try {
+ if ((fac = factory) != null &&
+ (wt = fac.newThread(this)) != null) {
+ wt.start();
+ return true;
+ }
+ } catch (Throwable rex) {
+ ex = rex;
+ }
+ deregisterWorker(wt, ex); // clean up and return false
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helps and/or blocks until the given task is done.
+ *
+ * @param joiner the joining worker
+ * @param task the task
+ * @return task status on exit
+ */
+ final int awaitJoin(WorkQueue joiner, ForkJoinTask<?> task) {
+ int s = 0;
+ if (task != null && (s = task.status) >= 0 && joiner != null) {
+ ForkJoinTask<?> prevJoin = joiner.currentJoin;
+ joiner.currentJoin = task;
+ do {} while (joiner.tryRemoveAndExec(task) && // process local tasks
+ (s = task.status) >= 0);
+ if (s >= 0 && (task instanceof CountedCompleter))
+ s = helpComplete(joiner, (CountedCompleter<?>)task);
+ long cc = 0; // for stability checks
+ while (s >= 0 && (s = task.status) >= 0) {
+ if ((s = tryHelpStealer(joiner, task)) == 0 &&
+ (s = task.status) >= 0) {
+ if (!tryCompensate(cc))
+ cc = ctl;
+ else {
+ if (task.trySetSignal() && (s = task.status) >= 0) {
+ synchronized (task) {
+ if (task.status >= 0) {
+ try { // see ForkJoinTask
+ task.wait(); // for explanation
+ } catch (InterruptedException ie) {
+ }
+ }
+ else
+ task.notifyAll();
+ }
+ }
+ long c; // reactivate
+ do {} while (!U.compareAndSwapLong
+ (this, CTL, c = ctl,
+ ((c & ~AC_MASK) |
+ ((c & AC_MASK) + AC_UNIT))));
+ }
+ }
+ }
+ joiner.currentJoin = prevJoin;
+ }
+ return s;
+ }
+
+ /**
+ * Stripped-down variant of awaitJoin used by timed joins. Tries
+ * to help join only while there is continuous progress. (Caller
+ * will then enter a timed wait.)
+ *
+ * @param joiner the joining worker
+ * @param task the task
+ */
+ final void helpJoinOnce(WorkQueue joiner, ForkJoinTask<?> task) {
+ int s;
+ if (joiner != null && task != null && (s = task.status) >= 0) {
+ ForkJoinTask<?> prevJoin = joiner.currentJoin;
+ joiner.currentJoin = task;
+ do {} while (joiner.tryRemoveAndExec(task) && // process local tasks
+ (s = task.status) >= 0);
+ if (s >= 0) {
+ if (task instanceof CountedCompleter)
+ helpComplete(joiner, (CountedCompleter<?>)task);
+ do {} while (task.status >= 0 &&
+ tryHelpStealer(joiner, task) > 0);
+ }
+ joiner.currentJoin = prevJoin;
+ }
+ }
/**
* Returns a (probably) non-empty steal queue, if one is found
@@ -2234,25 +2043,19 @@
* caller if, by the time it tries to use the queue, it is empty.
*/
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)
+ int r = ThreadLocalRandom.current().nextInt();
+ for (;;) {
+ int ps = plock, m; WorkQueue[] ws; WorkQueue q;
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) {
+ for (int j = (m + 1) << 2; j >= 0; --j) {
+ if ((q = ws[(((r - j) << 1) | 1) & m]) != null &&
+ q.base - q.top < 0)
return q;
- checkSum += b;
- }
- if ((k = (k + 1) & m) == origin) {
- if (oldSum == (oldSum = checkSum))
- break;
- checkSum = 0;
}
}
+ if (plock == ps)
+ return null;
}
- return null;
}
/**
@@ -2262,33 +2065,35 @@
* find tasks either.
*/
final void helpQuiescePool(WorkQueue w) {
- ForkJoinTask<?> ps = w.currentSteal; // save context
- int wc = w.config;
+ ForkJoinTask<?> ps = w.currentSteal;
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) {
+ long c; WorkQueue q; ForkJoinTask<?> t; int b;
+ while ((t = w.nextLocalTask()) != null)
+ t.doExec();
+ if ((q = findNonEmptyStealQueue()) != null) {
if (!active) { // re-establish active count
active = true;
- U.getAndAddLong(this, CTL, AC_UNIT);
+ do {} while (!U.compareAndSwapLong
+ (this, CTL, c = ctl,
+ ((c & ~AC_MASK) |
+ ((c & AC_MASK) + AC_UNIT))));
}
- if ((t = q.pollAt(q.base)) != null) {
+ if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != 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);
+ long nc = ((c = ctl) & ~AC_MASK) | ((c & AC_MASK) - AC_UNIT);
+ if ((int)(nc >> AC_SHIFT) + parallelism == 0)
+ break; // bypass decrement-then-increment
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))
+ else if ((int)((c = ctl) >> AC_SHIFT) + parallelism <= 0 &&
+ U.compareAndSwapLong
+ (this, CTL, c, ((c & ~AC_MASK) |
+ ((c & AC_MASK) + AC_UNIT))))
break;
}
}
@@ -2300,12 +2105,12 @@
*/
final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
for (ForkJoinTask<?> t;;) {
- WorkQueue q;
+ WorkQueue q; int b;
if ((t = w.nextLocalTask()) != null)
return t;
if ((q = findNonEmptyStealQueue()) == null)
return null;
- if ((t = q.pollAt(q.base)) != null)
+ if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null)
return t;
}
}
@@ -2313,7 +2118,7 @@
/**
* 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
+ * idea about task granularity. In essence by offering this
* method, we ask users only about tradeoffs in overhead vs
* expected throughput and its variance, rather than how finely to
* partition tasks.
@@ -2351,11 +2156,15 @@
* many of these by further considering the number of "idle"
* threads, that are known to have zero queued tasks, so
* compensate by a factor of (#idle/#active) threads.
+ *
+ * Note: The approximation of #busy workers as #active workers is
+ * not very good under current signalling scheme, and should be
+ * improved.
*/
static int getSurplusQueuedTaskCount() {
Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
- if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
- int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
+ if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) {
+ int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).parallelism;
int n = (q = wt.workQueue).top - q.base;
int a = (int)(pool.ctl >> AC_SHIFT) + p;
return n - (a > (p >>>= 1) ? 0 :
@@ -2370,203 +2179,170 @@
// Termination
/**
- * Possibly initiates and/or completes termination.
+ * Possibly initiates and/or completes termination. The caller
+ * triggering termination runs three passes through workQueues:
+ * (0) Setting termination status, followed by wakeups of queued
+ * workers; (1) cancelling all tasks; (2) interrupting lagging
+ * threads (likely in external tasks, but possibly also blocked in
+ * joins). Each pass repeats previous steps because of potential
+ * lagging thread creation.
*
* @param now if true, unconditionally terminate, else only
* if no work and no active workers
- * @param enable if true, terminate when next possible
- * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+ * @param enable if true, enable shutdown when next possible
+ * @return true if now terminating or terminated
*/
- private int tryTerminate(boolean now, boolean enable) {
- int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
-
- while ((rs = runState) >= 0) {
- if (!enable || this == common) // cannot shutdown
- return 1;
- else if (rs == 0)
- tryInitialize(false); // ensure initialized
- else
- U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+ private boolean tryTerminate(boolean now, boolean enable) {
+ int ps;
+ if (this == common) // cannot shut down
+ return false;
+ if ((ps = plock) >= 0) { // enable by setting plock
+ if (!enable)
+ return false;
+ if ((ps & PL_LOCK) != 0 ||
+ !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+ ps = acquirePlock();
+ int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN;
+ if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+ releasePlock(nps);
}
-
- if ((rs & STOP) == 0) { // try to initiate termination
- if (!now) { // check quiescence
- for (long oldSum = 0L;;) { // repeat until stable
- WorkQueue[] ws; WorkQueue w; int b;
- long checkSum = ctl;
- 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) {
- checkSum += (b = w.base);
- if (w.currentSteal != null || b != w.top)
- return 0; // retry if internal caller
- }
+ for (long c;;) {
+ if (((c = ctl) & STOP_BIT) != 0) { // already terminating
+ if ((short)(c >>> TC_SHIFT) + parallelism <= 0) {
+ synchronized (this) {
+ notifyAll(); // signal when 0 workers
+ }
+ }
+ return true;
+ }
+ if (!now) { // check if idle & no tasks
+ WorkQueue[] ws; WorkQueue w;
+ if ((int)(c >> AC_SHIFT) + parallelism > 0)
+ return false;
+ if ((ws = workQueues) != null) {
+ for (int i = 0; i < ws.length; ++i) {
+ if ((w = ws[i]) != null &&
+ (!w.isEmpty() ||
+ ((i & 1) != 0 && w.eventCount >= 0))) {
+ signalWork(ws, w);
+ return false;
}
}
- if (oldSum == (oldSum = checkSum))
- break;
}
}
- do {} while (!U.compareAndSwapInt(this, RUNSTATE,
- rs = runState, rs | STOP));
- }
-
- 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) {
+ if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) {
+ for (int pass = 0; pass < 3; ++pass) {
+ WorkQueue[] ws; WorkQueue w; Thread wt;
+ if ((ws = workQueues) != null) {
+ int n = ws.length;
+ for (int i = 0; i < n; ++i) {
+ if ((w = ws[i]) != null) {
+ w.qlock = -1;
+ if (pass > 0) {
+ w.cancelAll();
+ if (pass > 1 && (wt = w.owner) != null) {
+ if (!wt.isInterrupted()) {
+ try {
+ wt.interrupt();
+ } catch (Throwable ignore) {
+ }
+ }
+ U.unpark(wt);
+ }
}
}
}
+ // Wake up workers parked on event queue
+ int i, e; long cc; Thread p;
+ while ((e = (int)(cc = ctl) & E_MASK) != 0 &&
+ (i = e & SMASK) < n && i >= 0 &&
+ (w = ws[i]) != null) {
+ long nc = ((long)(w.nextWait & E_MASK) |
+ ((cc + AC_UNIT) & AC_MASK) |
+ (cc & (TC_MASK|STOP_BIT)));
+ if (w.eventCount == (e | INT_SIGN) &&
+ U.compareAndSwapLong(this, CTL, cc, nc)) {
+ w.eventCount = (e + E_SEQ) & E_MASK;
+ w.qlock = -1;
+ if ((p = w.parker) != null)
+ U.unpark(p);
+ }
+ }
}
}
}
- if (oldSum == (oldSum = checkSum))
- break;
- }
-
- if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
- runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
- synchronized (this) {
- notifyAll(); // for awaitTermination
- }
- }
-
- 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);
- }
- }
+ // external operations on common pool
/**
- * 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.
+ * Returns common pool queue for a thread that has submitted at
+ * least one task.
*/
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;
+ Submitter z; ForkJoinPool p; WorkQueue[] ws; int m, r;
+ return ((z = submitters.get()) != null &&
+ (p = common) != null &&
+ (ws = p.workQueues) != null &&
+ (m = ws.length - 1) >= 0) ?
+ ws[m & z.seed & SQMASK] : null;
}
/**
- * Performs tryUnpush for an external submitter.
+ * Tries to pop the given task from submitter's queue in common pool.
*/
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));
+ WorkQueue joiner; ForkJoinTask<?>[] a; int m, s;
+ Submitter z = submitters.get();
+ WorkQueue[] ws = workQueues;
+ boolean popped = false;
+ if (z != null && ws != null && (m = ws.length - 1) >= 0 &&
+ (joiner = ws[z.seed & m & SQMASK]) != null &&
+ joiner.base != (s = joiner.top) &&
+ (a = joiner.array) != null) {
+ long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
+ if (U.getObject(a, j) == task &&
+ U.compareAndSwapInt(joiner, QLOCK, 0, 1)) {
+ if (joiner.top == s && joiner.array == a &&
+ U.compareAndSwapObject(a, j, task, null)) {
+ joiner.top = s - 1;
+ popped = true;
+ }
+ joiner.qlock = 0;
+ }
+ }
+ return popped;
}
- /**
- * 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;
+ final int externalHelpComplete(CountedCompleter<?> task) {
+ WorkQueue joiner; int m, j;
+ Submitter z = submitters.get();
+ WorkQueue[] ws = workQueues;
+ int s = 0;
+ if (z != null && ws != null && (m = ws.length - 1) >= 0 &&
+ (joiner = ws[(j = z.seed) & m & SQMASK]) != null && task != null) {
+ int scans = m + m + 1;
+ long c = 0L; // for stability check
+ j |= 1; // poll odd queues
+ for (int k = scans; ; j += 2) {
+ WorkQueue q;
+ if ((s = task.status) < 0)
+ break;
+ else if (joiner.externalPopAndExecCC(task))
+ k = scans;
+ else if ((s = task.status) < 0)
+ break;
+ else if ((q = ws[j & m]) != null && q.pollAndExecCC(task))
+ k = scans;
+ else if (--k < 0) {
+ if (c == (c = ctl))
+ break;
+ k = scans;
+ }
+ }
+ }
+ return s;
}
// Exported methods
@@ -2578,11 +2354,6 @@
* 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
- * because it does not hold {@link
- * java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool() {
this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
@@ -2598,10 +2369,6 @@
* @param parallelism the parallelism level
* @throws IllegalArgumentException if parallelism less than or
* equal to zero, or greater than implementation limit
- * @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")}
*/
public ForkJoinPool(int parallelism) {
this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
@@ -2626,10 +2393,6 @@
* @throws IllegalArgumentException if parallelism less than or
* equal to zero, or greater than implementation limit
* @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")}
*/
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
@@ -2638,7 +2401,7 @@
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
- asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
+ (asyncMode ? FIFO_QUEUE : LIFO_QUEUE),
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
@@ -2669,7 +2432,8 @@
this.workerNamePrefix = workerNamePrefix;
this.factory = factory;
this.ueh = handler;
- this.config = (parallelism & SMASK) | mode;
+ this.mode = (short)mode;
+ this.parallelism = (short)parallelism;
long np = (long)(-parallelism); // offset ctl counts
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
@@ -2686,6 +2450,7 @@
*
* @return the common pool instance
* @since 1.8
+ * @hide
*/
public static ForkJoinPool commonPool() {
// assert common != null : "static init error";
@@ -2714,7 +2479,7 @@
public <T> T invoke(ForkJoinTask<T> task) {
if (task == null)
throw new NullPointerException();
- externalSubmit(task);
+ externalPush(task);
return task.join();
}
@@ -2727,7 +2492,9 @@
* scheduled for execution
*/
public void execute(ForkJoinTask<?> task) {
- externalSubmit(task);
+ if (task == null)
+ throw new NullPointerException();
+ externalPush(task);
}
// AbstractExecutorService methods
@@ -2745,7 +2512,7 @@
job = (ForkJoinTask<?>) task;
else
job = new ForkJoinTask.RunnableExecuteAction(task);
- externalSubmit(job);
+ externalPush(job);
}
/**
@@ -2759,7 +2526,10 @@
* scheduled for execution
*/
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
- return externalSubmit(task);
+ if (task == null)
+ throw new NullPointerException();
+ externalPush(task);
+ return task;
}
/**
@@ -2768,7 +2538,9 @@
* scheduled for execution
*/
public <T> ForkJoinTask<T> submit(Callable<T> task) {
- return externalSubmit(new ForkJoinTask.AdaptedCallable<T>(task));
+ ForkJoinTask<T> job = new ForkJoinTask.AdaptedCallable<T>(task);
+ externalPush(job);
+ return job;
}
/**
@@ -2777,7 +2549,9 @@
* scheduled for execution
*/
public <T> ForkJoinTask<T> submit(Runnable task, T result) {
- return externalSubmit(new ForkJoinTask.AdaptedRunnable<T>(task, result));
+ ForkJoinTask<T> job = new ForkJoinTask.AdaptedRunnable<T>(task, result);
+ externalPush(job);
+ return job;
}
/**
@@ -2793,7 +2567,8 @@
job = (ForkJoinTask<?>) task;
else
job = new ForkJoinTask.AdaptedRunnableAction(task);
- return externalSubmit(job);
+ externalPush(job);
+ return job;
}
/**
@@ -2804,21 +2579,23 @@
// In previous versions of this class, this method constructed
// a task to run ForkJoinTask.invokeAll, but now external
// invocation of multiple tasks is at least as efficient.
- ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+ ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ boolean done = false;
try {
for (Callable<T> t : tasks) {
ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
futures.add(f);
- externalSubmit(f);
+ externalPush(f);
}
for (int i = 0, size = futures.size(); i < size; i++)
((ForkJoinTask<?>)futures.get(i)).quietlyJoin();
+ done = true;
return futures;
- } catch (Throwable t) {
- for (int i = 0, size = futures.size(); i < size; i++)
- futures.get(i).cancel(false);
- throw t;
+ } finally {
+ if (!done)
+ for (int i = 0, size = futures.size(); i < size; i++)
+ futures.get(i).cancel(false);
}
}
@@ -2848,7 +2625,7 @@
*/
public int getParallelism() {
int par;
- return ((par = config & SMASK) > 0) ? par : 1;
+ return ((par = parallelism) > 0) ? par : 1;
}
/**
@@ -2856,9 +2633,10 @@
*
* @return the targeted parallelism level of the common pool
* @since 1.8
+ * @hide
*/
public static int getCommonPoolParallelism() {
- return COMMON_PARALLELISM;
+ return commonParallelism;
}
/**
@@ -2870,7 +2648,7 @@
* @return the number of worker threads
*/
public int getPoolSize() {
- return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+ return parallelism + (short)(ctl >>> TC_SHIFT);
}
/**
@@ -2880,7 +2658,7 @@
* @return {@code true} if this pool uses async mode
*/
public boolean getAsyncMode() {
- return (config & FIFO_QUEUE) != 0;
+ return mode == FIFO_QUEUE;
}
/**
@@ -2911,7 +2689,7 @@
* @return the number of active threads
*/
public int getActiveThreadCount() {
- int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+ int r = parallelism + (int)(ctl >> AC_SHIFT);
return (r <= 0) ? 0 : r; // suppress momentarily negative values
}
@@ -2927,7 +2705,7 @@
* @return {@code true} if all threads are currently idle
*/
public boolean isQuiescent() {
- return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+ return parallelism + (int)(ctl >> AC_SHIFT) <= 0;
}
/**
@@ -2942,8 +2720,7 @@
* @return the number of steals
*/
public long getStealCount() {
- AuxState sc = auxState;
- long count = (sc == null) ? 0L : sc.stealCount;
+ long count = stealCount;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
@@ -3020,11 +2797,10 @@
* @return the next submission, or {@code null} if none
*/
protected ForkJoinTask<?> pollSubmission() {
- 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)
+ WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+ if ((ws = workQueues) != null) {
+ for (int i = 0; i < ws.length; i += 2) {
+ if ((w = ws[i]) != null && (t = w.poll()) != null)
return t;
}
}
@@ -3074,8 +2850,7 @@
public String toString() {
// Use a single pass through workQueues to collect counts
long qt = 0L, qs = 0L; int rc = 0;
- AuxState sc = auxState;
- long st = (sc == null) ? 0L : sc.stealCount;
+ long st = stealCount;
long c = ctl;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
@@ -3093,16 +2868,16 @@
}
}
}
- int pc = (config & SMASK);
+ int pc = parallelism;
int tc = pc + (short)(c >>> TC_SHIFT);
int ac = pc + (int)(c >> AC_SHIFT);
if (ac < 0) // ignore transient negative
ac = 0;
- int rs = runState;
- String level = ((rs & TERMINATED) != 0 ? "Terminated" :
- (rs & STOP) != 0 ? "Terminating" :
- (rs & SHUTDOWN) != 0 ? "Shutting down" :
- "Running");
+ String level;
+ if ((c & STOP_BIT) != 0)
+ level = (tc == 0) ? "Terminated" : "Terminating";
+ else
+ level = plock < 0 ? "Shutting down" : "Running";
return super.toString() +
"[" + level +
", parallelism = " + pc +
@@ -3119,15 +2894,10 @@
* Possibly initiates an orderly shutdown in which previously
* submitted tasks are executed, but no new tasks will be
* accepted. Invocation has no effect on execution state if this
- * is the {@link #commonPool()}, and no additional effect if
+ * is the {@code commonPool()}, and no additional effect if
* already shut down. Tasks that are in the process of being
* submitted concurrently during the course of this method may or
* may not be rejected.
- *
- * @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")}
*/
public void shutdown() {
checkPermission();
@@ -3137,7 +2907,7 @@
/**
* Possibly attempts to cancel and/or stop all tasks, and reject
* all subsequently submitted tasks. Invocation has no effect on
- * execution state if this is the {@link #commonPool()}, and no
+ * execution state if this is the {@code commonPool()}, and no
* additional effect if already shut down. Otherwise, tasks that
* are in the process of being submitted or executed concurrently
* during the course of this method may or may not be
@@ -3147,10 +2917,6 @@
* (unlike the case for some other Executors).
*
* @return an empty list
- * @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")}
*/
public List<Runnable> shutdownNow() {
checkPermission();
@@ -3164,7 +2930,9 @@
* @return {@code true} if all tasks have completed following shut down
*/
public boolean isTerminated() {
- return (runState & TERMINATED) != 0;
+ long c = ctl;
+ return ((c & STOP_BIT) != 0L &&
+ (short)(c >>> TC_SHIFT) + parallelism <= 0);
}
/**
@@ -3181,8 +2949,9 @@
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
- int rs = runState;
- return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+ long c = ctl;
+ return ((c & STOP_BIT) != 0L &&
+ (short)(c >>> TC_SHIFT) + parallelism > 0);
}
/**
@@ -3191,14 +2960,14 @@
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
- return (runState & SHUTDOWN) != 0;
+ return plock < 0;
}
/**
* Blocks until all tasks have completed execution after a
* shutdown request, or the timeout occurs, or the current thread
- * is interrupted, whichever happens first. Because the {@link
- * #commonPool()} never terminates until program shutdown, when
+ * is interrupted, whichever happens first. Because the {@code
+ * commonPool()} never terminates until program shutdown, when
* applied to the common pool, this method is equivalent to {@link
* #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
*
@@ -3257,20 +3026,19 @@
}
long startTime = System.nanoTime();
WorkQueue[] ws;
- int r = 0, wl;
+ int r = 0, m;
boolean found = true;
while (!isQuiescent() && (ws = workQueues) != null &&
- (wl = ws.length) > 0) {
+ (m = ws.length - 1) >= 0) {
if (!found) {
if ((System.nanoTime() - startTime) > nanos)
return false;
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) {
+ for (int j = (m + 1) << 2; j >= 0; --j) {
+ ForkJoinTask<?> t; WorkQueue q; int b;
+ if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) {
found = true;
if ((t = q.pollAt(b)) != null)
t.doExec();
@@ -3283,7 +3051,7 @@
/**
* Waits and/or attempts to assist performing tasks indefinitely
- * until the {@link #commonPool()} {@link #isQuiescent}.
+ * until the {@code commonPool()} {@link #isQuiescent}.
*/
static void quiesceCommonPool() {
common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
@@ -3294,8 +3062,8 @@
* in {@link ForkJoinPool}s.
*
* <p>A {@code ManagedBlocker} provides two methods. Method
- * {@link #isReleasable} must return {@code true} if blocking is
- * not necessary. Method {@link #block} blocks the current thread
+ * {@code isReleasable} must return {@code true} if blocking is
+ * not necessary. Method {@code block} blocks the current thread
* if necessary (perhaps internally invoking {@code isReleasable}
* before actually blocking). These actions are performed by any
* thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}.
@@ -3309,7 +3077,7 @@
*
* <p>For example, here is a ManagedBlocker based on a
* ReentrantLock:
- * <pre> {@code
+ * <pre> {@code
* class ManagedLocker implements ManagedBlocker {
* final ReentrantLock lock;
* boolean hasLock = false;
@@ -3326,7 +3094,7 @@
*
* <p>Here is a class that possibly blocks waiting for an
* item on a given queue:
- * <pre> {@code
+ * <pre> {@code
* class QueueTaker<E> implements ManagedBlocker {
* final BlockingQueue<E> queue;
* volatile E item = null;
@@ -3364,46 +3132,37 @@
}
/**
- * Runs the given possibly blocking task. When {@linkplain
- * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this
- * method possibly arranges for a spare thread to be activated if
- * necessary to ensure sufficient parallelism while the current
- * thread is blocked in {@link ManagedBlocker#block blocker.block()}.
+ * Blocks in accord with the given blocker. If the current thread
+ * is a {@link ForkJoinWorkerThread}, this method possibly
+ * arranges for a spare thread to be activated if necessary to
+ * ensure sufficient parallelism while the current thread is blocked.
*
- * <p>This method repeatedly calls {@code blocker.isReleasable()} and
- * {@code blocker.block()} until either method returns {@code true}.
- * Every call to {@code blocker.block()} is preceded by a call to
- * {@code blocker.isReleasable()} that returned {@code false}.
- *
- * <p>If not running in a ForkJoinPool, this method is
+ * <p>If the caller is not a {@link ForkJoinTask}, this method is
* behaviorally equivalent to
- * <pre> {@code
+ * <pre> {@code
* while (!blocker.isReleasable())
* if (blocker.block())
- * break;}</pre>
+ * return;
+ * }</pre>
*
- * If running in a ForkJoinPool, the pool may first be expanded to
- * ensure sufficient parallelism available during the call to
- * {@code blocker.block()}.
+ * If the caller is a {@code ForkJoinTask}, then the pool may
+ * first be expanded to ensure parallelism, and later adjusted.
*
- * @param blocker the blocker task
- * @throws InterruptedException if {@code blocker.block()} did so
+ * @param blocker the blocker
+ * @throws InterruptedException if blocker.block did so
*/
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
- ForkJoinPool p;
- ForkJoinWorkerThread wt;
Thread t = Thread.currentThread();
- if ((t instanceof ForkJoinWorkerThread) &&
- (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
- WorkQueue w = wt.workQueue;
+ if (t instanceof ForkJoinWorkerThread) {
+ ForkJoinPool p = ((ForkJoinWorkerThread)t).pool;
while (!blocker.isReleasable()) {
- if (p.tryCompensate(w)) {
+ if (p.tryCompensate(p.ctl)) {
try {
do {} while (!blocker.isReleasable() &&
!blocker.block());
} finally {
- U.getAndAddLong(p, CTL, AC_UNIT);
+ p.incrementActiveCount();
}
break;
}
@@ -3428,40 +3187,49 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
private static final long CTL;
- private static final long RUNSTATE;
+ private static final long PARKBLOCKER;
private static final int ABASE;
private static final int ASHIFT;
+ private static final long STEALCOUNT;
+ private static final long PLOCK;
+ private static final long INDEXSEED;
+ private static final long QBASE;
+ private static final long QLOCK;
static {
+ // initialize field offsets for CAS etc
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ForkJoinPool.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);
+ (k.getDeclaredField("ctl"));
+ STEALCOUNT = U.objectFieldOffset
+ (k.getDeclaredField("stealCount"));
+ PLOCK = U.objectFieldOffset
+ (k.getDeclaredField("plock"));
+ INDEXSEED = U.objectFieldOffset
+ (k.getDeclaredField("indexSeed"));
+ Class<?> tk = Thread.class;
+ PARKBLOCKER = U.objectFieldOffset
+ (tk.getDeclaredField("parkBlocker"));
+ Class<?> wk = WorkQueue.class;
+ QBASE = U.objectFieldOffset
+ (wk.getDeclaredField("base"));
+ QLOCK = U.objectFieldOffset
+ (wk.getDeclaredField("qlock"));
+ Class<?> ak = ForkJoinTask[].class;
+ ABASE = U.arrayBaseOffset(ak);
+ int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
+ throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (ReflectiveOperationException e) {
+ } catch (Exception 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;
-
- int commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
- try {
- String p = System.getProperty
- ("java.util.concurrent.ForkJoinPool.common.maximumSpares");
- if (p != null)
- commonMaxSpares = Integer.parseInt(p);
- } catch (Exception ignore) {}
- COMMON_MAX_SPARES = commonMaxSpares;
-
+ submitters = new ThreadLocal<Submitter>();
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
modifyThreadPermission = new RuntimePermission("modifyThread");
@@ -3469,18 +3237,18 @@
common = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<ForkJoinPool>() {
public ForkJoinPool run() { return makeCommonPool(); }});
-
- // report 1 even if threads disabled
- COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
+ int par = common.parallelism; // report 1 even if threads disabled
+ commonParallelism = par > 0 ? par : 1;
}
/**
* Creates and returns the common pool, respecting user settings
* specified via system properties.
*/
- static ForkJoinPool makeCommonPool() {
+ private static ForkJoinPool makeCommonPool() {
int parallelism = -1;
- ForkJoinWorkerThreadFactory factory = null;
+ ForkJoinWorkerThreadFactory factory
+ = defaultForkJoinWorkerThreadFactory;
UncaughtExceptionHandler handler = null;
try { // ignore exceptions in accessing/parsing properties
String pp = System.getProperty
@@ -3499,52 +3267,14 @@
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;
+ (parallelism = Runtime.getRuntime().availableProcessors() - 1) < 0)
+ parallelism = 0;
if (parallelism > MAX_CAP)
parallelism = MAX_CAP;
return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
"ForkJoinPool.commonPool-worker-");
}
- /**
- * Factory for innocuous worker threads.
- */
- private static final class InnocuousForkJoinWorkerThreadFactory
- implements ForkJoinWorkerThreadFactory {
-
- /**
- * An ACC to restrict permissions for the factory itself.
- * The constructed workers have no permissions set.
- */
- 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 java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
- public ForkJoinWorkerThread run() {
- return new ForkJoinWorkerThread.
- InnocuousForkJoinWorkerThread(pool);
- }}, innocuousAcc);
- }
- }
-
}
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
index a8d97db..3a1a381 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -7,17 +7,13 @@
package java.util.concurrent;
import java.io.Serializable;
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
import java.util.concurrent.locks.ReentrantLock;
-
-// BEGIN android-note
-// removed java 9 code
-// END android-note
+import java.lang.reflect.Constructor;
/**
* Abstract base class for tasks that run within a {@link ForkJoinPool}.
@@ -28,8 +24,8 @@
*
* <p>A "main" {@code ForkJoinTask} begins execution when it is
* explicitly submitted to a {@link ForkJoinPool}, or, if not already
- * engaged in a ForkJoin computation, commenced in the {@link
- * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * engaged in a ForkJoin computation, commenced in the {@code
+ * ForkJoinPool.commonPool()} via {@link #fork}, {@link #invoke}, or
* related methods. Once started, it will usually in turn start other
* subtasks. As indicated by the name of this class, many programs
* using {@code ForkJoinTask} employ only methods {@link #fork} and
@@ -70,10 +66,9 @@
* 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
- * CountedCompleter}) often fall into this category. (2) To minimize
- * resource impact, tasks should be small; ideally performing only the
- * (possibly) blocking action. (3) Unless the {@link
+ * tasks that are never joined often fall into this category.
+ * (2) To minimize resource impact, tasks should be small; ideally
+ * performing only the (possibly) blocking action. (3) Unless the {@link
* ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
* blocked tasks is known to be less than the pool's {@link
* ForkJoinPool#getParallelism} level, the pool cannot guarantee that
@@ -116,13 +111,11 @@
* <p>The ForkJoinTask class is not usually directly subclassed.
* Instead, you subclass one of the abstract classes that support a
* particular style of fork/join processing, typically {@link
- * RecursiveAction} for most computations that do not return results,
- * {@link RecursiveTask} for those that do, and {@link
- * CountedCompleter} for those in which completed actions trigger
- * other actions. Normally, a concrete ForkJoinTask subclass declares
- * fields comprising its parameters, established in a constructor, and
- * then defines a {@code compute} method that somehow uses the control
- * methods supplied by this base class.
+ * RecursiveAction} for most computations that do not return results
+ * and {@link RecursiveTask} for those that do. Normally, a concrete
+ * ForkJoinTask subclass declares fields comprising its parameters,
+ * established in a constructor, and then defines a {@code compute}
+ * method that somehow uses the control methods supplied by this base class.
*
* <p>Method {@link #join} and its variants are appropriate for use
* only when completion dependencies are acyclic; that is, the
@@ -134,9 +127,9 @@
* may be of use in constructing custom subclasses for problems that
* are not statically structured as DAGs. To support such usages, a
* ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
- * value using {@link #setForkJoinTaskTag} or {@link
- * #compareAndSetForkJoinTaskTag} and checked using {@link
- * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * value using {@code setForkJoinTaskTag} or {@code
+ * compareAndSetForkJoinTaskTag} and checked using {@code
+ * getForkJoinTaskTag}. The ForkJoinTask implementation does not use
* these {@code protected} methods or tags for any purpose, but they
* may be of use in the construction of specialized subclasses. For
* example, parallel graph traversals can use the supplied methods to
@@ -176,6 +169,8 @@
* @since 1.7
* @author Doug Lea
*/
+// android-note: Removed references to hidden apis commonPool, CountedCompleter
+// etc.
public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/*
@@ -264,22 +259,15 @@
}
/**
- * If not done, sets SIGNAL status and performs Object.wait(timeout).
- * This task may or may not be done on exit. Ignores interrupts.
+ * Tries to set SIGNAL status unless already completed. Used by
+ * ForkJoinPool. Other variants are directly incorporated into
+ * externalAwaitDone etc.
*
- * @param timeout using Object.wait conventions.
+ * @return true if successful
*/
- final void internalWait(long timeout) {
- 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) { }
- else
- notifyAll();
- }
- }
+ final boolean trySetSignal() {
+ int s = status;
+ return s >= 0 && U.compareAndSwapInt(this, STATUS, s, s | SIGNAL);
}
/**
@@ -287,29 +275,35 @@
* @return status upon completion
*/
private int externalAwaitDone() {
- 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;
- do {
- if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0) {
- try {
- wait(0L);
- } catch (InterruptedException ie) {
- interrupted = true;
+ int s;
+ ForkJoinPool cp = ForkJoinPool.common;
+ if ((s = status) >= 0) {
+ if (cp != null) {
+ if (this instanceof CountedCompleter)
+ s = cp.externalHelpComplete((CountedCompleter<?>)this);
+ else if (cp.tryExternalUnpush(this))
+ s = doExec();
+ }
+ if (s >= 0 && (s = status) >= 0) {
+ boolean interrupted = false;
+ do {
+ if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
}
+ else
+ notifyAll();
}
- else
- notifyAll();
}
- }
- } while ((s = status) >= 0);
- if (interrupted)
- Thread.currentThread().interrupt();
+ } while ((s = status) >= 0);
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
}
return s;
}
@@ -319,22 +313,22 @@
*/
private int externalInterruptibleAwaitDone() throws InterruptedException {
int s;
+ ForkJoinPool cp = ForkJoinPool.common;
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();
- }
+ if ((s = status) >= 0 && cp != null) {
+ if (this instanceof CountedCompleter)
+ cp.externalHelpComplete((CountedCompleter<?>)this);
+ else if (cp.tryExternalUnpush(this))
+ doExec();
+ }
+ while ((s = status) >= 0) {
+ if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0)
+ wait();
+ else
+ notifyAll();
}
}
}
@@ -354,7 +348,7 @@
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(w = (wt = (ForkJoinWorkerThread)t).workQueue).
tryUnpush(this) && (s = doExec()) < 0 ? s :
- wt.pool.awaitJoin(w, this, 0L) :
+ wt.pool.awaitJoin(w, this) :
externalAwaitDone();
}
@@ -367,8 +361,7 @@
int s; Thread t; ForkJoinWorkerThread wt;
return (s = doExec()) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
- (wt = (ForkJoinWorkerThread)t).pool.
- awaitJoin(wt.workQueue, this, 0L) :
+ (wt = (ForkJoinWorkerThread)t).pool.awaitJoin(wt.workQueue, this) :
externalAwaitDone();
}
@@ -409,8 +402,7 @@
ExceptionNode next;
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<Object> exceptionTableRefQueue) {
+ ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) {
super(task, exceptionTableRefQueue);
this.ex = ex;
this.next = next;
@@ -436,8 +428,7 @@
int i = h & (t.length - 1);
for (ExceptionNode e = t[i]; ; e = e.next) {
if (e == null) {
- t[i] = new ExceptionNode(this, ex, t[i],
- exceptionTableRefQueue);
+ t[i] = new ExceptionNode(this, ex, t[i]);
break;
}
if (e.get() == this) // already present
@@ -516,20 +507,22 @@
}
/**
- * Returns a rethrowable exception for this task, if available.
- * To provide accurate stack traces, if the exception was not
- * thrown by the current thread, we try to create a new exception
- * of the same type as the one thrown, but with the recorded
- * exception as its cause. If there is no such constructor, we
- * instead try to use a no-arg constructor, followed by initCause,
- * to the same effect. If none of these apply, or any fail due to
- * other exceptions, we return the recorded exception, which is
- * still correct, although it may contain a misleading stack
- * trace.
+ * Returns a rethrowable exception for the given task, if
+ * available. To provide accurate stack traces, if the exception
+ * was not thrown by the current thread, we try to create a new
+ * exception of the same type as the one thrown, but with the
+ * recorded exception as its cause. If there is no such
+ * constructor, we instead try to use a no-arg constructor,
+ * followed by initCause, to the same effect. If none of these
+ * apply, or any fail due to other exceptions, we return the
+ * recorded exception, which is still correct, although it may
+ * contain a misleading stack trace.
*
* @return the exception, or null if none
*/
private Throwable getThrowableException() {
+ if ((status & DONE_MASK) != EXCEPTIONAL)
+ return null;
int h = System.identityHashCode(this);
ExceptionNode e;
final ReentrantLock lock = exceptionTableLock;
@@ -546,19 +539,21 @@
Throwable ex;
if (e == null || (ex = e.ex) == null)
return null;
- if (e.thrower != Thread.currentThread().getId()) {
+ if (false && e.thrower != Thread.currentThread().getId()) {
+ Class<? extends Throwable> ec = ex.getClass();
try {
Constructor<?> noArgCtor = null;
- // public ctors only
- for (Constructor<?> c : ex.getClass().getConstructors()) {
+ Constructor<?>[] cs = ec.getConstructors();// public ctors only
+ for (int i = 0; i < cs.length; ++i) {
+ Constructor<?> c = cs[i];
Class<?>[] ps = c.getParameterTypes();
if (ps.length == 0)
noArgCtor = c;
else if (ps.length == 1 && ps[0] == Throwable.class)
- return (Throwable)c.newInstance(ex);
+ return (Throwable)(c.newInstance(ex));
}
if (noArgCtor != null) {
- Throwable wx = (Throwable)noArgCtor.newInstance();
+ Throwable wx = (Throwable)(noArgCtor.newInstance());
wx.initCause(ex);
return wx;
}
@@ -569,7 +564,7 @@
}
/**
- * Polls stale refs and removes them. Call only while holding lock.
+ * Poll stale refs and remove them. Call only while holding lock.
*/
private static void expungeStaleExceptions() {
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
@@ -596,7 +591,7 @@
}
/**
- * If lock is available, polls stale refs and removes them.
+ * If lock is available, poll stale refs and remove them.
* Called from ForkJoinPool when pools become quiescent.
*/
static final void helpExpungeStaleExceptions() {
@@ -611,23 +606,21 @@
}
/**
- * A version of "sneaky throw" to relay exceptions.
+ * A version of "sneaky throw" to relay exceptions
*/
static void rethrow(Throwable ex) {
- ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
+ if (ex != null)
+ ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
}
/**
* The sneaky part of sneaky throw, relying on generics
* limitations to evade compiler complaints about rethrowing
- * unchecked exceptions.
+ * unchecked exceptions
*/
@SuppressWarnings("unchecked") static <T extends Throwable>
- void uncheckedThrow(Throwable t) throws T {
- if (t != null)
- throw (T)t; // rely on vacuous cast
- else
- throw new Error("Unknown Exception");
+ void uncheckedThrow(Throwable t) throws T {
+ throw (T)t; // rely on vacuous cast
}
/**
@@ -644,8 +637,8 @@
/**
* Arranges to asynchronously execute this task in the pool the
- * current task is running in, if applicable, or using the {@link
- * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}. While
+ * current task is running in, if applicable, or using the {@code
+ * ForkJoinPool.commonPool()} if not {@link #inForkJoinPool}. While
* it is not necessarily enforced, it is a usage error to fork a
* task more than once unless it has completed and been
* reinitialized. Subsequent modifications to the state of this
@@ -943,6 +936,7 @@
* invocations of {@code join} and related operations.
*
* @since 1.8
+ * @hide
*/
public final void quietlyComplete() {
setCompletion(NORMAL);
@@ -962,10 +956,11 @@
public final V get() throws InterruptedException, ExecutionException {
int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
doJoin() : externalInterruptibleAwaitDone();
+ Throwable ex;
if ((s &= DONE_MASK) == CANCELLED)
throw new CancellationException();
- if (s == EXCEPTIONAL)
- throw new ExecutionException(getThrowableException());
+ if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
+ throw new ExecutionException(ex);
return getRawResult();
}
@@ -985,46 +980,75 @@
*/
public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- int s;
- long nanos = unit.toNanos(timeout);
if (Thread.interrupted())
throw new InterruptedException();
- if ((s = status) >= 0 && nanos > 0L) {
- long d = System.nanoTime() + nanos;
- long deadline = (d == 0L) ? 1L : d; // avoid 0
+ // Messy in part because we measure in nanosecs, but wait in millisecs
+ int s; long ms;
+ long ns = unit.toNanos(timeout);
+ ForkJoinPool cp;
+ if ((s = status) >= 0 && ns > 0L) {
+ long deadline = System.nanoTime() + ns;
+ ForkJoinPool p = null;
+ ForkJoinPool.WorkQueue w = null;
Thread t = Thread.currentThread();
if (t instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
- s = wt.pool.awaitJoin(wt.workQueue, this, deadline);
+ p = wt.pool;
+ w = wt.workQueue;
+ p.helpJoinOnce(w, this); // no retries on failure
}
- else if ((s = ((this instanceof CountedCompleter) ?
- ForkJoinPool.common.externalHelpComplete(
- (CountedCompleter<?>)this, 0) :
- ForkJoinPool.common.tryExternalUnpush(this) ?
- doExec() : 0)) >= 0) {
- long ns, ms; // measure in nanosecs, but wait in millisecs
- while ((s = status) >= 0 &&
- (ns = deadline - System.nanoTime()) > 0L) {
- if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
- U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0)
- wait(ms); // OK to throw InterruptedException
- else
- notifyAll();
+ else if ((cp = ForkJoinPool.common) != null) {
+ if (this instanceof CountedCompleter)
+ cp.externalHelpComplete((CountedCompleter<?>)this);
+ else if (cp.tryExternalUnpush(this))
+ doExec();
+ }
+ boolean canBlock = false;
+ boolean interrupted = false;
+ try {
+ while ((s = status) >= 0) {
+ if (w != null && w.qlock < 0)
+ cancelIgnoringExceptions(this);
+ else if (!canBlock) {
+ if (p == null || p.tryCompensate(p.ctl))
+ canBlock = true;
+ }
+ else {
+ if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
+ U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0) {
+ try {
+ wait(ms);
+ } catch (InterruptedException ie) {
+ if (p == null)
+ interrupted = true;
+ }
+ }
+ else
+ notifyAll();
+ }
}
+ if ((s = status) < 0 || interrupted ||
+ (ns = deadline - System.nanoTime()) <= 0L)
+ break;
}
}
+ } finally {
+ if (p != null && canBlock)
+ p.incrementActiveCount();
}
+ if (interrupted)
+ throw new InterruptedException();
}
- if (s >= 0)
- s = status;
if ((s &= DONE_MASK) != NORMAL) {
+ Throwable ex;
if (s == CANCELLED)
throw new CancellationException();
if (s != EXCEPTIONAL)
throw new TimeoutException();
- throw new ExecutionException(getThrowableException());
+ if ((ex = getThrowableException()) != null)
+ throw new ExecutionException(ex);
}
return getRawResult();
}
@@ -1050,10 +1074,10 @@
/**
* Possibly executes tasks until the pool hosting the current task
- * {@linkplain ForkJoinPool#isQuiescent is quiescent}. This
- * method may be of use in designs in which many tasks are forked,
- * but none are explicitly joined, instead executing them until
- * all are processed.
+ * {@link ForkJoinPool#isQuiescent is quiescent}. This method may
+ * be of use in designs in which many tasks are forked, but none
+ * are explicitly joined, instead executing them until all are
+ * processed.
*/
public static void helpQuiesce() {
Thread t;
@@ -1089,12 +1113,10 @@
}
/**
- * Returns the pool hosting the current thread, or {@code null}
- * if the current thread is executing outside of any ForkJoinPool.
+ * Returns the pool hosting the current task execution, or null
+ * if this task is executing outside of any ForkJoinPool.
*
- * <p>This method returns {@code null} if and only if {@link
- * #inForkJoinPool} returns {@code false}.
- *
+ * @see #inForkJoinPool
* @return the pool, or {@code null} if none
*/
public static ForkJoinPool getPool() {
@@ -1261,25 +1283,6 @@
null;
}
- /**
- * If the current thread is operating in a ForkJoinPool,
- * unschedules and returns, without executing, a task externally
- * submitted to the pool, if one is available. Availability may be
- * transient, so a {@code null} result does not necessarily imply
- * quiescence of the pool. This method is designed primarily to
- * support extensions, and is unlikely to be useful otherwise.
- *
- * @return a task, or {@code null} if none are available
- * @since 9
- * @hide
- */
- // android-changed - hidden
- protected static ForkJoinTask<?> pollSubmission() {
- Thread t;
- return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
- ((ForkJoinWorkerThread)t).pool.pollSubmission() : null;
- }
-
// tag operations
/**
@@ -1287,22 +1290,24 @@
*
* @return the tag for this task
* @since 1.8
+ * @hide
*/
public final short getForkJoinTaskTag() {
return (short)status;
}
/**
- * Atomically sets the tag value for this task and returns the old value.
+ * Atomically sets the tag value for this task.
*
- * @param newValue the new tag value
+ * @param tag the tag value
* @return the previous value of the tag
* @since 1.8
+ * @hide
*/
- public final short setForkJoinTaskTag(short newValue) {
+ public final short setForkJoinTaskTag(short tag) {
for (int s;;) {
if (U.compareAndSwapInt(this, STATUS, s = status,
- (s & ~SMASK) | (newValue & SMASK)))
+ (s & ~SMASK) | (tag & SMASK)))
return (short)s;
}
}
@@ -1315,24 +1320,25 @@
* before processing, otherwise exiting because the node has
* already been visited.
*
- * @param expect the expected tag value
- * @param update the new tag value
+ * @param e the expected tag value
+ * @param tag the new tag value
* @return {@code true} if successful; i.e., the current value was
- * equal to {@code expect} and was changed to {@code update}.
+ * equal to e and is now tag.
* @since 1.8
+ * @hide
*/
- public final boolean compareAndSetForkJoinTaskTag(short expect, short update) {
+ public final boolean compareAndSetForkJoinTaskTag(short e, short tag) {
for (int s;;) {
- if ((short)(s = status) != expect)
+ if ((short)(s = status) != e)
return false;
if (U.compareAndSwapInt(this, STATUS, s,
- (s & ~SMASK) | (update & SMASK)))
+ (s & ~SMASK) | (tag & SMASK)))
return true;
}
}
/**
- * Adapter for Runnables. This implements RunnableFuture
+ * Adaptor for Runnables. This implements RunnableFuture
* to be compliant with AbstractExecutorService constraints
* when used in ForkJoinPool.
*/
@@ -1353,7 +1359,7 @@
}
/**
- * Adapter for Runnables without results.
+ * Adaptor for Runnables without results
*/
static final class AdaptedRunnableAction extends ForkJoinTask<Void>
implements RunnableFuture<Void> {
@@ -1370,7 +1376,7 @@
}
/**
- * Adapter for Runnables in which failure forces worker exception.
+ * Adaptor for Runnables in which failure forces worker exception
*/
static final class RunnableExecuteAction extends ForkJoinTask<Void> {
final Runnable runnable;
@@ -1388,7 +1394,7 @@
}
/**
- * Adapter for Callables.
+ * Adaptor for Callables
*/
static final class AdaptedCallable<T> extends ForkJoinTask<T>
implements RunnableFuture<T> {
@@ -1461,8 +1467,6 @@
/**
* Saves this task to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData the current run status and the exception thrown
* during execution, or {@code null} if none
*/
@@ -1474,10 +1478,6 @@
/**
* Reconstitutes this task 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1488,7 +1488,7 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final sun.misc.Unsafe U;
private static final long STATUS;
static {
@@ -1496,11 +1496,12 @@
exceptionTableRefQueue = new ReferenceQueue<Object>();
exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
try {
+ U = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = ForkJoinTask.class;
STATUS = U.objectFieldOffset
- (ForkJoinTask.class.getDeclaredField("status"));
- } catch (ReflectiveOperationException e) {
+ (k.getDeclaredField("status"));
+ } catch (Exception e) {
throw new Error(e);
}
}
-
}
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index 664d56e..ae28700 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -6,9 +6,6 @@
package java.util.concurrent;
-import java.security.AccessControlContext;
-import java.security.ProtectionDomain;
-
/**
* A thread managed by a {@link ForkJoinPool}, which executes
* {@link ForkJoinTask}s.
@@ -35,10 +32,6 @@
* completes. This leads to a visibility race, that is tolerated
* by requiring that the workQueue field is only accessed by the
* owning thread.
- *
- * Support for (non-public) subclass InnocuousForkJoinWorkerThread
- * 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
@@ -58,18 +51,6 @@
}
/**
- * Version for InnocuousForkJoinWorkerThread.
- */
- ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
- AccessControlContext acc) {
- super(threadGroup, null, "aForkJoinWorkerThread");
- U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
- eraseThreadLocals(); // clear before registering
- this.pool = pool;
- this.workQueue = pool.registerWorker(this);
- }
-
- /**
* Returns the pool hosting this thread.
*
* @return the pool
@@ -89,7 +70,7 @@
* @return the index number
*/
public int getPoolIndex() {
- return workQueue.getPoolIndex();
+ return workQueue.poolIndex >>> 1; // ignore odd/even tag bit
}
/**
@@ -121,124 +102,21 @@
* {@link ForkJoinTask}s.
*/
public void run() {
- if (workQueue.array == null) { // only run once
- Throwable exception = null;
- try {
- onStart();
- pool.runWorker(workQueue);
- } catch (Throwable ex) {
- exception = ex;
- } finally {
- try {
- onTermination(exception);
- } catch (Throwable ex) {
- if (exception == null)
- exception = ex;
- } finally {
- pool.deregisterWorker(this, exception);
- }
- }
- }
- }
-
- /**
- * 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 {
+ Throwable exception = null;
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, 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 =
- createThreadGroup();
-
- /** An AccessControlContext supporting no privileges */
- private static final AccessControlContext INNOCUOUS_ACC =
- new AccessControlContext(
- new ProtectionDomain[] {
- new ProtectionDomain(null, null)
- });
-
- InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
- super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
- }
-
- @Override // to erase ThreadLocals
- void afterTopLevelExec() {
- eraseThreadLocals();
- }
-
- @Override // to always report system loader
- public ClassLoader getContextClassLoader() {
- return ClassLoader.getSystemClassLoader();
- }
-
- @Override // to silently fail
- public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
-
- @Override // paranoically
- 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() {
+ onStart();
+ pool.runWorker(workQueue);
+ } catch (Throwable ex) {
+ exception = ex;
+ } finally {
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);
+ onTermination(exception);
+ } catch (Throwable ex) {
+ if (exception == null)
+ exception = ex;
+ } finally {
+ pool.deregisterWorker(this, exception);
}
- // fall through if null as cannot-happen safeguard
- throw new Error("Cannot create ThreadGroup");
}
}
-
}
diff --git a/luni/src/main/java/java/util/concurrent/Future.java b/luni/src/main/java/java/util/concurrent/Future.java
index 28d2de5..32e8145 100644
--- a/luni/src/main/java/java/util/concurrent/Future.java
+++ b/luni/src/main/java/java/util/concurrent/Future.java
@@ -23,9 +23,8 @@
*
* <p>
* <b>Sample Usage</b> (Note that the following classes are all
- * made-up.)
- *
- * <pre> {@code
+ * made-up.) <p>
+ * <pre> {@code
* interface ArchiveSearcher { String search(String target); }
* class App {
* ExecutorService executor = ...
@@ -47,9 +46,9 @@
* The {@link FutureTask} class is an implementation of {@code Future} that
* 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
+ * <pre> {@code
* FutureTask<String> future =
- * new FutureTask<>(new Callable<String>() {
+ * new FutureTask<String>(new Callable<String>() {
* public String call() {
* return searcher.search(target);
* }});
diff --git a/luni/src/main/java/java/util/concurrent/FutureTask.java b/luni/src/main/java/java/util/concurrent/FutureTask.java
index ed42817..5e24fc8 100644
--- a/luni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/luni/src/main/java/java/util/concurrent/FutureTask.java
@@ -367,7 +367,7 @@
throws InterruptedException {
// The code below is very delicate, to achieve these goals:
// - call nanoTime exactly once for each call to park
- // - if nanos <= 0L, return promptly without allocation or nanoTime
+ // - if nanos <= 0, return promptly without allocation or nanoTime
// - if nanos == Long.MIN_VALUE, don't underflow
// - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
// and we suffer a spurious wakeup, we will do no worse than
@@ -467,7 +467,7 @@
(FutureTask.class.getDeclaredField("runner"));
WAITERS = U.objectFieldOffset
(FutureTask.class.getDeclaredField("waiters"));
- } catch (ReflectiveOperationException e) {
+ } catch (Exception e) {
throw new Error(e);
}
diff --git a/luni/src/main/java/java/util/concurrent/Helpers.java b/luni/src/main/java/java/util/concurrent/Helpers.java
deleted file mode 100644
index 9051e2f..0000000
--- a/luni/src/main/java/java/util/concurrent/Helpers.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Written by 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 java.util.concurrent;
-
-import java.util.Collection;
-
-/** Shared implementation code for java.util.concurrent. */
-class Helpers {
- private Helpers() {} // non-instantiable
-
- /**
- * An implementation of Collection.toString() suitable for classes
- * with locks. Instead of holding a lock for the entire duration of
- * toString(), or acquiring a lock for each call to Iterator.next(),
- * we hold the lock only during the call to toArray() (less
- * disruptive to other threads accessing the collection) and follows
- * the maxim "Never call foreign code while holding a lock".
- */
- static String collectionToString(Collection<?> c) {
- final Object[] a = c.toArray();
- final int size = a.length;
- if (size == 0)
- return "[]";
- int charLength = 0;
-
- // Replace every array element with its string representation
- for (int i = 0; i < size; i++) {
- Object e = a[i];
- // Extreme compatibility with AbstractCollection.toString()
- String s = (e == c) ? "(this Collection)" : objectToString(e);
- a[i] = s;
- charLength += s.length();
- }
-
- return toString(a, size, charLength);
- }
-
- /**
- * Like Arrays.toString(), but caller guarantees that size > 0,
- * each element with index 0 <= i < size is a non-null String,
- * and charLength is the sum of the lengths of the input Strings.
- */
- static String toString(Object[] a, int size, int charLength) {
- // assert a != null;
- // assert size > 0;
-
- // Copy each string into a perfectly sized char[]
- // Length of [ , , , ] == 2 * size
- final char[] chars = new char[charLength + 2 * size];
- chars[0] = '[';
- int j = 1;
- for (int i = 0; i < size; i++) {
- if (i > 0) {
- chars[j++] = ',';
- chars[j++] = ' ';
- }
- String s = (String) a[i];
- int len = s.length();
- s.getChars(0, len, chars, j);
- j += len;
- }
- chars[j] = ']';
- // assert j == chars.length - 1;
- return new String(chars);
- }
-
- /** Optimized form of: key + "=" + val */
- static String mapEntryToString(Object key, Object val) {
- final String k, v;
- final int klen, vlen;
- final char[] chars =
- new char[(klen = (k = objectToString(key)).length()) +
- (vlen = (v = objectToString(val)).length()) + 1];
- k.getChars(0, klen, chars, 0);
- chars[klen] = '=';
- v.getChars(0, vlen, chars, klen + 1);
- return new String(chars);
- }
-
- private static String objectToString(Object x) {
- // Extreme compatibility with StringBuilder.append(null)
- String s;
- return (x == null || (s = x.toString()) == null) ? "null" : s;
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
index b1d196d..64b0bf1 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -10,11 +10,8 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
-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;
// BEGIN android-note
// removed link to collections framework docs
@@ -43,7 +40,7 @@
*
* @since 1.6
* @author Doug Lea
- * @param <E> the type of elements held in this deque
+ * @param <E> the type of elements held in this collection
*/
public class LinkedBlockingDeque<E>
extends AbstractQueue<E>
@@ -289,8 +286,8 @@
// BlockingDeque methods
/**
- * @throws IllegalStateException if this deque is full
- * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
*/
public void addFirst(E e) {
if (!offerFirst(e))
@@ -298,7 +295,7 @@
}
/**
- * @throws IllegalStateException if this deque is full
+ * @throws IllegalStateException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void addLast(E e) {
@@ -383,7 +380,7 @@
lock.lockInterruptibly();
try {
while (!linkFirst(node)) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -406,7 +403,7 @@
lock.lockInterruptibly();
try {
while (!linkLast(node)) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -488,7 +485,7 @@
try {
E x;
while ( (x = unlinkFirst()) == null) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -506,7 +503,7 @@
try {
E x;
while ( (x = unlinkLast()) == null) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -597,7 +594,8 @@
*
* <p>This method is equivalent to {@link #addLast}.
*
- * @throws IllegalStateException if this deque is full
+ * @throws IllegalStateException if the element cannot be added at this
+ * time due to capacity restrictions
* @throws NullPointerException if the specified element is null
*/
public boolean add(E e) {
@@ -734,8 +732,8 @@
// Stack methods
/**
- * @throws IllegalStateException if this deque is full
- * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalStateException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
*/
public void push(E e) {
addFirst(e);
@@ -825,7 +823,7 @@
// * @throws ClassCastException {@inheritDoc}
// * @throws NullPointerException {@inheritDoc}
// * @throws IllegalArgumentException {@inheritDoc}
-// * @throws IllegalStateException if this deque is full
+// * @throws IllegalStateException {@inheritDoc}
// * @see #add(Object)
// */
// public boolean addAll(Collection<? extends E> c) {
@@ -895,7 +893,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -930,7 +928,26 @@
}
public String toString() {
- return Helpers.collectionToString(this);
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ Node<E> p = first;
+ if (p == null)
+ return "[]";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (;;) {
+ E e = p.item;
+ sb.append(e == this ? "(this Collection)" : e);
+ p = p.next;
+ if (p == null)
+ return sb.append(']').toString();
+ sb.append(',').append(' ');
+ }
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -960,8 +977,12 @@
* 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).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this deque in proper sequence
*/
@@ -974,8 +995,12 @@
* sequential order. The elements will be returned in order from
* last (tail) to first (head).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this deque in reverse order
*/
@@ -984,11 +1009,11 @@
}
/**
- * Base class for LinkedBlockingDeque iterators.
+ * Base class for Iterators for LinkedBlockingDeque
*/
private abstract class AbstractItr implements Iterator<E> {
/**
- * The next node to return in next().
+ * The next node to return in next()
*/
Node<E> next;
@@ -1097,149 +1122,9 @@
Node<E> nextNode(Node<E> n) { return n.prev; }
}
- /** 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 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 = q.first) != null) &&
- h.next != null) {
- Object[] a = new Object[n];
- final ReentrantLock lock = q.lock;
- int i = 0;
- Node<E> p = current;
- lock.lock();
- try {
- if (p != null || (p = q.first) != null) {
- do {
- if ((a[i] = p.item) != null)
- ++i;
- } while ((p = p.next) != null && i < n);
- }
- } finally {
- lock.unlock();
- }
- if ((current = p) == null) {
- est = 0L;
- exhausted = true;
- }
- else if ((est -= i) < 0L)
- est = 0L;
- 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) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingDeque<E> q = this.queue;
- final ReentrantLock lock = q.lock;
- if (!exhausted) {
- E e = null;
- lock.lock();
- try {
- 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;
- }
- }
- return false;
- }
-
- public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
- }
- }
-
- /**
- * Returns a {@link Spliterator} over the elements in this deque.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this deque
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return new LBDSpliterator<E>(this);
- }
-
/**
* Saves this deque to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData The capacity (int), followed by elements (each an
* {@code Object}) in the proper order, followed by a null
*/
@@ -1262,10 +1147,6 @@
/**
* Reconstitutes this deque 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index 86ed04a..0719828 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -6,16 +6,13 @@
package java.util.concurrent;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
-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;
// BEGIN android-note
// removed link to collections framework docs
@@ -46,7 +43,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -88,7 +85,7 @@
*/
/**
- * Linked list node class.
+ * Linked list node class
*/
static class Node<E> {
E item;
@@ -351,7 +348,7 @@
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -433,7 +430,7 @@
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -478,7 +475,11 @@
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
- return (count.get() > 0) ? head.next.item : null;
+ Node<E> first = head.next;
+ if (first == null)
+ return null;
+ else
+ return first.item;
} finally {
takeLock.unlock();
}
@@ -597,7 +598,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -632,7 +633,25 @@
}
public String toString() {
- return Helpers.collectionToString(this);
+ fullyLock();
+ try {
+ Node<E> p = head.next;
+ if (p == null)
+ return "[]";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (;;) {
+ E e = p.item;
+ sb.append(e == this ? "(this Collection)" : e);
+ p = p.next;
+ if (p == null)
+ return sb.append(']').toString();
+ sb.append(',').append(' ');
+ }
+ } finally {
+ fullyUnlock();
+ }
}
/**
@@ -715,8 +734,12 @@
* 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).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this queue in proper sequence
*/
@@ -750,26 +773,34 @@
return current != null;
}
+ /**
+ * Returns the next live successor of p, or null if no such.
+ *
+ * Unlike other traversal methods, iterators need to handle both:
+ * - dequeued nodes (p.next == p)
+ * - (possibly multiple) interior removed nodes (p.item == null)
+ */
+ private Node<E> nextNode(Node<E> p) {
+ for (;;) {
+ Node<E> s = p.next;
+ if (s == p)
+ return head.next;
+ if (s == null || s.item != null)
+ return s;
+ p = s;
+ }
+ }
+
public E next() {
fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
+ E x = currentElement;
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;
- }
- }
+ current = nextNode(current);
+ currentElement = (current == null) ? null : current.item;
+ return x;
} finally {
fullyUnlock();
}
@@ -796,146 +827,9 @@
}
}
- /** 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 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 = q.head.next) != null) &&
- h.next != null) {
- Object[] a = new Object[n];
- int i = 0;
- Node<E> p = current;
- q.fullyLock();
- try {
- if (p != null || (p = q.head.next) != null) {
- do {
- if ((a[i] = p.item) != null)
- ++i;
- } while ((p = p.next) != null && i < n);
- }
- } finally {
- q.fullyUnlock();
- }
- if ((current = p) == null) {
- est = 0L;
- exhausted = true;
- }
- else if ((est -= i) < 0L)
- est = 0L;
- 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) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingQueue<E> q = this.queue;
- if (!exhausted) {
- E e = null;
- q.fullyLock();
- try {
- if (current == null)
- current = q.head.next;
- while (current != null) {
- e = current.item;
- current = current.next;
- if (e != null)
- break;
- }
- } finally {
- q.fullyUnlock();
- }
- if (current == null)
- exhausted = true;
- if (e != null) {
- action.accept(e);
- return true;
- }
- }
- return false;
- }
-
- public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
- }
- }
-
- /**
- * Returns a {@link Spliterator} over the elements in this queue.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this queue
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return new LBQSpliterator<E>(this);
- }
-
/**
* Saves this queue to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData The capacity is emitted (int), followed by all of
* its elements (each an {@code Object}) in the proper order,
* followed by a null
@@ -961,10 +855,6 @@
/**
* 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index 185ebfd..db48420 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -7,15 +7,11 @@
package java.util.concurrent;
import java.util.AbstractQueue;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
-import java.util.Spliterator;
-import java.util.Spliterators;
import java.util.concurrent.locks.LockSupport;
-import java.util.function.Consumer;
// BEGIN android-note
// removed link to collections framework docs
@@ -54,7 +50,7 @@
*
* @since 1.7
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class LinkedTransferQueue<E> extends AbstractQueue<E>
implements TransferQueue<E>, java.io.Serializable {
@@ -186,7 +182,7 @@
* of costly-to-reclaim garbage caused by the sequential "next"
* links of nodes starting at old forgotten head nodes: As first
* described in detail by Boehm
- * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC
+ * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC
* delays noticing that any arbitrarily old node has become
* garbage, all newer dead nodes will also be unreclaimed.
* (Similar issues arise in non-GC environments.) To cope with
@@ -427,12 +423,12 @@
// CAS methods for fields
final boolean casNext(Node cmp, Node val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class;
- return U.compareAndSwapObject(this, ITEM, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
/**
@@ -440,7 +436,7 @@
* only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
- U.putObject(this, ITEM, item); // relaxed write
+ UNSAFE.putObject(this, itemOffset, item); // relaxed write
this.isData = isData;
}
@@ -449,7 +445,7 @@
* only after CASing head field, so uses relaxed write.
*/
final void forgetNext() {
- U.putObject(this, NEXT, this);
+ UNSAFE.putObject(this, nextOffset, this);
}
/**
@@ -462,8 +458,8 @@
* else we don't care).
*/
final void forgetContents() {
- U.putObject(this, ITEM, this);
- U.putObject(this, WAITER, null);
+ UNSAFE.putObject(this, itemOffset, this);
+ UNSAFE.putObject(this, waiterOffset, null);
}
/**
@@ -509,19 +505,21 @@
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;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long itemOffset;
+ private static final long nextOffset;
+ private static final long waiterOffset;
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) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Node.class;
+ itemOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("item"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ waiterOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("waiter"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -538,15 +536,15 @@
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
}
private boolean casSweepVotes(int cmp, int val) {
- return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+ return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
}
/*
@@ -557,6 +555,12 @@
private static final int SYNC = 2; // for transfer, take
private static final int TIMED = 3; // for timed poll, tryTransfer
+ @SuppressWarnings("unchecked")
+ static <E> E cast(Object item) {
+ // assert item == null || item.getClass() != Node.class;
+ return (E) item;
+ }
+
/**
* Implements all queuing methods. See above for explanation.
*
@@ -593,8 +597,7 @@
break; // unless slack < 2
}
LockSupport.unpark(p.waiter);
- @SuppressWarnings("unchecked") E itemE = (E) item;
- return itemE;
+ return LinkedTransferQueue.<E>cast(item);
}
}
Node n = p.next;
@@ -672,15 +675,15 @@
if (item != e) { // matched
// assert item != s;
s.forgetContents(); // avoid garbage
- @SuppressWarnings("unchecked") E itemE = (E) item;
- return itemE;
+ return LinkedTransferQueue.<E>cast(item);
}
- else if (w.isInterrupted() || (timed && nanos <= 0L)) {
- unsplice(pred, s); // try to unlink and cancel
- if (s.casItem(e, s)) // return normally if lost CAS
- return e;
+ if ((w.isInterrupted() || (timed && nanos <= 0)) &&
+ s.casItem(e, s)) { // cancel
+ unsplice(pred, s);
+ return e;
}
- else if (spins < 0) { // establish spins at/near front
+
+ if (spins < 0) { // establish spins at/near front
if ((spins = spinsFor(pred, s.isData)) > 0)
randomYields = ThreadLocalRandom.current();
}
@@ -732,25 +735,32 @@
}
/**
- * Returns the first unmatched data node, or null if none.
- * Callers must recheck if the returned node's item field is null
- * or self-linked before using.
+ * Returns the first unmatched node of the given mode, or null if
+ * none. Used by methods isEmpty, hasWaitingConsumer.
*/
- final Node firstDataNode() {
- restartFromHead: for (;;) {
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p)
- return p;
- }
- else if (item == null)
- break;
- if (p == (p = p.next))
- continue restartFromHead;
- }
- return null;
+ private Node firstOfMode(boolean isData) {
+ for (Node p = head; p != null; p = succ(p)) {
+ if (!p.isMatched())
+ return (p.isData == isData) ? p : null;
}
+ return null;
+ }
+
+ /**
+ * Returns the item in the first unmatched node with isData; or
+ * null if none. Used by peek.
+ */
+ private E firstDataItem() {
+ for (Node p = head; p != null; p = succ(p)) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p)
+ return LinkedTransferQueue.<E>cast(item);
+ }
+ else if (item == null)
+ return null;
+ }
+ return null;
}
/**
@@ -758,140 +768,23 @@
* Used by methods size and getWaitingConsumerCount.
*/
private int countOfMode(boolean data) {
- restartFromHead: for (;;) {
- int count = 0;
- for (Node p = head; p != null;) {
- if (!p.isMatched()) {
- if (p.isData != data)
- return 0;
- if (++count == Integer.MAX_VALUE)
- break; // @see Collection.size()
- }
- if (p == (p = p.next))
- continue restartFromHead;
- }
- return count;
- }
- }
-
- public String toString() {
- String[] a = null;
- restartFromHead: for (;;) {
- int charLength = 0;
- int size = 0;
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p) {
- if (a == null)
- a = new String[4];
- else if (size == a.length)
- a = Arrays.copyOf(a, 2 * size);
- String s = item.toString();
- a[size++] = s;
- charLength += s.length();
- }
- } else if (item == null)
+ int count = 0;
+ for (Node p = head; p != null; ) {
+ if (!p.isMatched()) {
+ if (p.isData != data)
+ return 0;
+ if (++count == Integer.MAX_VALUE) // saturated
break;
- if (p == (p = p.next))
- continue restartFromHead;
}
-
- if (size == 0)
- return "[]";
-
- return Helpers.toString(a, size, charLength);
+ Node n = p.next;
+ if (n != p)
+ p = n;
+ else {
+ count = 0;
+ p = head;
+ }
}
- }
-
- private Object[] toArrayInternal(Object[] a) {
- Object[] x = a;
- restartFromHead: for (;;) {
- int size = 0;
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p) {
- if (x == null)
- x = new Object[4];
- else if (size == x.length)
- x = Arrays.copyOf(x, 2 * (size + 4));
- x[size++] = item;
- }
- } else if (item == null)
- break;
- if (p == (p = p.next))
- continue restartFromHead;
- }
- if (x == null)
- return new Object[0];
- else if (a != null && size <= a.length) {
- if (a != x)
- System.arraycopy(x, 0, a, 0, size);
- if (size < a.length)
- a[size] = null;
- return a;
- }
- return (size == x.length) ? x : Arrays.copyOf(x, size);
- }
- }
-
- /**
- * Returns an array containing all of the elements in this queue, in
- * proper sequence.
- *
- * <p>The returned array will be "safe" in that no references to it are
- * maintained by this queue. (In other words, this method must allocate
- * a new array). The caller is thus free to modify the returned array.
- *
- * <p>This method acts as bridge between array-based and collection-based
- * APIs.
- *
- * @return an array containing all of the elements in this queue
- */
- public Object[] toArray() {
- return toArrayInternal(null);
- }
-
- /**
- * Returns an array containing all of the elements in this queue, in
- * proper sequence; the runtime type of the returned array is that of
- * the specified array. If the queue fits in the specified array, it
- * is returned therein. Otherwise, a new array is allocated with the
- * runtime type of the specified array and the size of this queue.
- *
- * <p>If this queue fits in the specified array with room to spare
- * (i.e., the array has more elements than this queue), the element in
- * the array immediately following the end of the queue is set to
- * {@code null}.
- *
- * <p>Like the {@link #toArray()} method, this method acts as bridge between
- * array-based and collection-based APIs. Further, this method allows
- * precise control over the runtime type of the output array, and may,
- * under certain circumstances, be used to save allocation costs.
- *
- * <p>Suppose {@code x} is a queue known to contain only strings.
- * The following code can be used to dump the queue into a newly
- * allocated array of {@code String}:
- *
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
- *
- * Note that {@code toArray(new Object[0])} is identical in function to
- * {@code toArray()}.
- *
- * @param a the array into which the elements of the queue are to
- * be stored, if it is big enough; otherwise, a new array of the
- * same runtime type is allocated for this purpose
- * @return an array containing all of the elements in this queue
- * @throws ArrayStoreException if the runtime type of the specified array
- * is not a supertype of the runtime type of every element in
- * this queue
- * @throws NullPointerException if the specified array is null
- */
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(T[] a) {
- if (a == null) throw new NullPointerException();
- return (T[]) toArrayInternal(a);
+ return count;
}
final class Itr implements Iterator<E> {
@@ -940,8 +833,7 @@
Object item = s.item;
if (s.isData) {
if (item != null && item != s) {
- @SuppressWarnings("unchecked") E itemE = (E) item;
- nextItem = itemE;
+ nextItem = LinkedTransferQueue.<E>cast(item);
nextNode = s;
return;
}
@@ -988,111 +880,6 @@
}
}
- /** A customized variant of Spliterators.IteratorSpliterator */
- 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
- boolean exhausted; // true when no more nodes
- LTQSpliterator() {}
-
- public Spliterator<E> trySplit() {
- 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));
- }
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public void forEachRemaining(Consumer<? super E> action) {
- Node p;
- if (action == null) throw new NullPointerException();
- if (!exhausted &&
- ((p = current) != null || (p = firstDataNode()) != null)) {
- exhausted = true;
- 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) {
- Node p;
- if (action == null) throw new NullPointerException();
- if (!exhausted &&
- ((p = current) != null || (p = firstDataNode()) != null)) {
- Object e;
- do {
- if ((e = p.item) == p)
- e = null;
- if (p == (p = p.next))
- p = firstDataNode();
- } while (e == null && p != null && p.isData);
- if ((current = p) == null)
- exhausted = true;
- if (e != null) {
- action.accept((E)e);
- return true;
- }
- }
- return false;
- }
-
- public long estimateSize() { return Long.MAX_VALUE; }
-
- public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
- }
- }
-
- /**
- * Returns a {@link Spliterator} over the elements in this queue.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
- * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} implements {@code trySplit} to permit limited
- * parallelism.
- *
- * @return a {@code Spliterator} over the elements in this queue
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return new LTQSpliterator<E>();
- }
-
/* -------------- Removal methods -------------- */
/**
@@ -1104,7 +891,7 @@
* @param s the node to be unspliced
*/
final void unsplice(Node pred, Node s) {
- s.waiter = null; // disable signals
+ s.forgetContents(); // forget unneeded fields
/*
* See above for rationale. Briefly: if pred still points to
* s, try to unlink s. If s cannot be unlinked, because it is
@@ -1372,8 +1159,12 @@
* 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).
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this queue in proper sequence
*/
@@ -1382,22 +1173,7 @@
}
public E peek() {
- restartFromHead: for (;;) {
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p) {
- @SuppressWarnings("unchecked") E e = (E) item;
- return e;
- }
- }
- else if (item == null)
- break;
- if (p == (p = p.next))
- continue restartFromHead;
- }
- return null;
- }
+ return firstDataItem();
}
/**
@@ -1406,24 +1182,15 @@
* @return {@code true} if this queue contains no elements
*/
public boolean isEmpty() {
- return firstDataNode() == null;
+ for (Node p = head; p != null; p = succ(p)) {
+ if (!p.isMatched())
+ return !p.isData;
+ }
+ return true;
}
public boolean hasWaitingConsumer() {
- restartFromHead: for (;;) {
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p)
- break;
- }
- else if (item == null)
- return true;
- if (p == (p = p.next))
- continue restartFromHead;
- }
- return false;
- }
+ return firstOfMode(false) != null;
}
/**
@@ -1470,16 +1237,15 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- 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 (item == null)
- break;
+ if (o == null) return false;
+ 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 (item == null)
+ break;
}
return false;
}
@@ -1499,8 +1265,6 @@
/**
* Saves this queue to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData All of the elements (each an {@code E}) in
* the proper order, followed by a null
*/
@@ -1515,10 +1279,6 @@
/**
* 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1535,19 +1295,21 @@
// Unsafe mechanics
- 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;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
+ private static final long tailOffset;
+ private static final long sweepVotesOffset;
static {
try {
- HEAD = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("tail"));
- SWEEPVOTES = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = LinkedTransferQueue.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ tailOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("tail"));
+ sweepVotesOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("sweepVotes"));
+ } catch (Exception e) {
throw new Error(e);
}
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
index 9b2a7a1..c5faf16 100644
--- a/luni/src/main/java/java/util/concurrent/Phaser.java
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -42,7 +42,7 @@
*
* <ul>
*
- * <li><b>Arrival.</b> Methods {@link #arrive} and
+ * <li> <b>Arrival.</b> Methods {@link #arrive} and
* {@link #arriveAndDeregister} record arrival. These methods
* do not block, but return an associated <em>arrival phase
* number</em>; that is, the phase number of the phaser to which
@@ -55,7 +55,7 @@
* flexible than, providing a barrier action to a {@code
* CyclicBarrier}.
*
- * <li><b>Waiting.</b> Method {@link #awaitAdvance} requires an
+ * <li> <b>Waiting.</b> Method {@link #awaitAdvance} requires an
* argument indicating an arrival phase number, and returns when
* the phaser advances to (or is already at) a different phase.
* Unlike similar constructions using {@code CyclicBarrier},
@@ -66,10 +66,9 @@
* state of the phaser. If necessary, you can perform any
* associated recovery within handlers of those exceptions,
* often after invoking {@code forceTermination}. Phasers may
- * also be used by tasks executing in a {@link ForkJoinPool}.
- * Progress is ensured if the pool's parallelismLevel can
- * accommodate the maximum number of simultaneously blocked
- * parties.
+ * also be used by tasks executing in a {@link ForkJoinPool},
+ * which will ensure sufficient parallelism to execute tasks
+ * when others are blocked waiting for a phase to advance.
*
* </ul>
*
@@ -125,7 +124,7 @@
* The typical idiom is for the method setting this up to first
* register, then start the actions, then deregister, as in:
*
- * <pre> {@code
+ * <pre> {@code
* void runTasks(List<Runnable> tasks) {
* final Phaser phaser = new Phaser(1); // "1" to register self
* // create and start threads
@@ -146,7 +145,7 @@
* <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
+ * <pre> {@code
* void startTasks(List<Runnable> tasks, final int iterations) {
* final Phaser phaser = new Phaser() {
* protected boolean onAdvance(int phase, int registeredParties) {
@@ -170,7 +169,7 @@
*
* If the main task must later await termination, it
* may re-register and then execute a similar loop:
- * <pre> {@code
+ * <pre> {@code
* // ...
* phaser.register();
* while (!phaser.isTerminated())
@@ -180,7 +179,7 @@
* in contexts where you are sure that the phase will never wrap around
* {@code Integer.MAX_VALUE}. For example:
*
- * <pre> {@code
+ * <pre> {@code
* void awaitPhase(Phaser phaser, int phase) {
* int p = phaser.register(); // assumes caller not already registered
* while (p < phase) {
@@ -200,7 +199,7 @@
* new Phaser())}, these tasks could then be started, for example by
* submitting to a pool:
*
- * <pre> {@code
+ * <pre> {@code
* void build(Task[] tasks, int lo, int hi, Phaser ph) {
* if (hi - lo > TASKS_PER_PHASER) {
* for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
@@ -301,7 +300,7 @@
}
/**
- * The parent of this phaser, or null if none.
+ * The parent of this phaser, or null if none
*/
private final Phaser parent;
@@ -359,7 +358,7 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+ if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -372,12 +371,13 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- U.compareAndSwapLong(this, STATE, s, n);
+ UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
- U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+ UNSAFE.compareAndSwapLong(this, stateOffset,
+ s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@@ -388,7 +388,7 @@
}
/**
- * Implementation of register, bulkRegister.
+ * Implementation of register, bulkRegister
*
* @param registrations number to add to both parties and
* unarrived fields. Must be greater than zero.
@@ -412,13 +412,14 @@
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
- else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+ else if (UNSAFE.compareAndSwapLong(this, stateOffset,
+ s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
- if (U.compareAndSwapLong(this, STATE, s, next))
+ if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
break;
}
else {
@@ -430,8 +431,8 @@
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
- while (!U.compareAndSwapLong
- (this, STATE, s,
+ while (!UNSAFE.compareAndSwapLong
+ (this, stateOffset, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@@ -462,8 +463,8 @@
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
- !U.compareAndSwapLong
- (this, STATE, s,
+ !UNSAFE.compareAndSwapLong
+ (this, stateOffset, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -652,7 +653,8 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+ if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
+ s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@@ -667,7 +669,7 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- if (!U.compareAndSwapLong(this, STATE, s, n))
+ if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@@ -783,7 +785,8 @@
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
- if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+ if (UNSAFE.compareAndSwapLong(root, stateOffset,
+ s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@@ -922,7 +925,7 @@
}
/**
- * Implementation of toString and string-based error messages.
+ * Implementation of toString and string-based error messages
*/
private String stateToString(long s) {
return super.toString() +
@@ -1031,7 +1034,7 @@
else {
try {
ForkJoinPool.managedBlock(node);
- } catch (InterruptedException cantHappen) {
+ } catch (InterruptedException ie) {
node.wasInterrupted = true;
}
}
@@ -1050,7 +1053,7 @@
}
/**
- * Wait nodes for Treiber stack representing wait queue.
+ * Wait nodes for Treiber stack representing wait queue
*/
static final class QNode implements ForkJoinPool.ManagedBlocker {
final Phaser phaser;
@@ -1087,34 +1090,40 @@
thread = null;
return true;
}
- if (timed &&
- (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
- thread = null;
- return true;
+ if (timed) {
+ if (nanos > 0L) {
+ nanos = deadline - System.nanoTime();
+ }
+ if (nanos <= 0L) {
+ thread = null;
+ return true;
+ }
}
return false;
}
public boolean block() {
- while (!isReleasable()) {
- if (timed)
- LockSupport.parkNanos(this, nanos);
- else
- LockSupport.park(this);
- }
- return true;
+ if (isReleasable())
+ return true;
+ else if (!timed)
+ LockSupport.park(this);
+ else if (nanos > 0L)
+ LockSupport.parkNanos(this, nanos);
+ return isReleasable();
}
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long stateOffset;
static {
try {
- STATE = U.objectFieldOffset
- (Phaser.class.getDeclaredField("state"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = Phaser.class;
+ stateOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("state"));
+ } catch (Exception e) {
throw new Error(e);
}
diff --git a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 2044406..40b3510 100644
--- a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -6,19 +6,9 @@
package java.util.concurrent;
-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.PriorityQueue;
-import java.util.Queue;
-import java.util.SortedSet;
-import java.util.Spliterator;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Consumer;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
@@ -53,7 +43,7 @@
* tie-breaking to comparable elements. To use it, you would insert a
* {@code new FIFOEntry(anEntry)} instead of a plain entry object.
*
- * <pre> {@code
+ * <pre> {@code
* class FIFOEntry<E extends Comparable<? super E>>
* implements Comparable<FIFOEntry<E>> {
* static final AtomicLong seq = new AtomicLong(0);
@@ -74,7 +64,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
@SuppressWarnings("unchecked")
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
@@ -132,12 +122,12 @@
private transient Comparator<? super E> comparator;
/**
- * Lock used for all public operations.
+ * Lock used for all public operations
*/
private final ReentrantLock lock;
/**
- * Condition for blocking when empty.
+ * Condition for blocking when empty
*/
private final Condition notEmpty;
@@ -260,7 +250,8 @@
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
- U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+ UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
+ 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@@ -642,7 +633,7 @@
}
/**
- * Identity-based version for use in Itr.remove.
+ * Identity-based version for use in Itr.remove
*/
void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
@@ -678,8 +669,48 @@
}
}
+ /**
+ * Returns an array containing all of the elements in this queue.
+ * The returned array elements are in no particular order.
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this queue. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this queue
+ */
+ public Object[] toArray() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return Arrays.copyOf(queue, size);
+ } finally {
+ lock.unlock();
+ }
+ }
+
public String toString() {
- return Helpers.collectionToString(this);
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ int n = size;
+ if (n == 0)
+ return "[]";
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (int i = 0; i < n; ++i) {
+ Object e = queue[i];
+ sb.append(e == this ? "(this Collection)" : e);
+ if (i != n - 1)
+ sb.append(',').append(' ');
+ }
+ return sb.append(']').toString();
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -738,29 +769,6 @@
}
/**
- * Returns an array containing all of the elements in this queue.
- * The returned array elements are in no particular order.
- *
- * <p>The returned array will be "safe" in that no references to it are
- * maintained by this queue. (In other words, this method must allocate
- * a new array). The caller is thus free to modify the returned array.
- *
- * <p>This method acts as bridge between array-based and collection-based
- * APIs.
- *
- * @return an array containing all of the elements in this queue
- */
- public Object[] toArray() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- return Arrays.copyOf(queue, size);
- } finally {
- lock.unlock();
- }
- }
-
- /**
* Returns an array containing all of the elements in this queue; the
* runtime type of the returned array is that of the specified array.
* The returned array elements are in no particular order.
@@ -782,7 +790,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -817,8 +825,12 @@
* Returns an iterator over the elements in this queue. The
* iterator does not return the elements in any particular order.
*
- * <p>The returned iterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ * <p>The returned iterator is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}, and guarantees to traverse
+ * elements as they existed upon construction of the iterator, and
+ * may (but is not guaranteed to) reflect any modifications
+ * subsequent to construction.
*
* @return an iterator over the elements in this queue
*/
@@ -864,9 +876,6 @@
* For compatibility with previous version of this class, elements
* are first copied to a java.util.PriorityQueue, which is then
* serialized.
- *
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
@@ -884,10 +893,6 @@
/**
* 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -901,93 +906,16 @@
}
}
- // 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(PriorityBlockingQueue<E> queue, Object[] array,
- int index, int fence) {
- this.queue = queue;
- this.array = array;
- this.index = index;
- this.fence = fence;
- }
-
- final int getFence() {
- int hi;
- if ((hi = fence) < 0)
- hi = fence = (array = queue.toArray()).length;
- return hi;
- }
-
- public PBQSpliterator<E> trySplit() {
- int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
- return (lo >= mid) ? null :
- new PBQSpliterator<E>(queue, array, lo, index = mid);
- }
-
- @SuppressWarnings("unchecked")
- public void forEachRemaining(Consumer<? super E> action) {
- 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) {
- if (action == null)
- throw new NullPointerException();
- if (getFence() > index && index >= 0) {
- @SuppressWarnings("unchecked") E e = (E) array[index++];
- action.accept(e);
- return true;
- }
- return false;
- }
-
- public long estimateSize() { return (long)(getFence() - index); }
-
- public int characteristics() {
- return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
- }
- }
-
- /**
- * Returns a {@link Spliterator} over the elements in this queue.
- *
- * <p>The returned spliterator is
- * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
- *
- * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
- * {@link Spliterator#NONNULL}.
- *
- * @implNote
- * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}.
- *
- * @return a {@code Spliterator} over the elements in this queue
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return new PBQSpliterator<E>(this, null, 0, -1);
- }
-
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long ALLOCATIONSPINLOCK;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long allocationSpinLockOffset;
static {
try {
- ALLOCATIONSPINLOCK = U.objectFieldOffset
- (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = PriorityBlockingQueue.class;
+ allocationSpinLockOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("allocationSpinLock"));
+ } catch (Exception e) {
throw new Error(e);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
index 8631a89..e3a6340 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveAction.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
@@ -16,7 +16,7 @@
* <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
* sort that sorts a given {@code long[]} array:
*
- * <pre> {@code
+ * <pre> {@code
* static class SortTask extends RecursiveAction {
* final long[] array; final int lo, hi;
* SortTask(long[] array, int lo, int hi) {
@@ -50,7 +50,7 @@
* SortTask(anArray)} and invoking it in a ForkJoinPool. As a more
* concrete simple example, the following task increments each element
* of an array:
- * <pre> {@code
+ * <pre> {@code
* class IncrementTask extends RecursiveAction {
* final long[] array; final int lo, hi;
* IncrementTask(long[] array, int lo, int hi) {
@@ -81,7 +81,7 @@
* performing leaf actions on unstolen tasks rather than further
* subdividing.
*
- * <pre> {@code
+ * <pre> {@code
* double sumOfSquares(ForkJoinPool pool, double[] array) {
* int n = array.length;
* Applyer a = new Applyer(array, 0, n, null);
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
index 5cba1da..d201bd6 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -11,11 +11,11 @@
*
* <p>For a classic example, here is a task computing Fibonacci numbers:
*
- * <pre> {@code
+ * <pre> {@code
* class Fibonacci extends RecursiveTask<Integer> {
* final int n;
* Fibonacci(int n) { this.n = n; }
- * protected Integer compute() {
+ * Integer compute() {
* if (n <= 1)
* return n;
* Fibonacci f1 = new Fibonacci(n - 1);
diff --git a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
index 604f180..7125233 100644
--- a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
+++ b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
@@ -19,11 +19,11 @@
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
/**
- * Returns {@code true} if this task is periodic. A periodic task may
+ * Returns true if this is a periodic task. A periodic task may
* re-run according to some schedule. A non-periodic task can be
* run only once.
*
- * @return {@code true} if this task is periodic
+ * @return true if this task is periodic
*/
boolean isPeriodic();
}
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index eae47b3..c07a5b9 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -41,7 +41,7 @@
* Here is a class with a method that sets up a ScheduledExecutorService
* to beep every ten seconds for an hour:
*
- * <pre> {@code
+ * <pre> {@code
* import static java.util.concurrent.TimeUnit.*;
* class BeeperControl {
* private final ScheduledExecutorService scheduler =
@@ -100,37 +100,23 @@
/**
* 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
+ * 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>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}.
- * </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.
+ * If any execution of the task
+ * encounters an exception, subsequent executions are suppressed.
+ * Otherwise, the task will only terminate via cancellation or
+ * termination of the executor. If any execution of this task
+ * takes longer than its period, then subsequent executions
+ * may start late, but will not concurrently execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
- * the series of repeated tasks. The future's {@link
- * Future#get() get()} method will never return normally,
- * and will throw an exception upon task cancellation or
- * abnormal termination of a task execution.
+ * the task, and whose {@code get()} method will throw an
+ * exception upon cancellation
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
@@ -145,21 +131,10 @@
* 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:
- * <ul>
- * <li>The task is {@linkplain Future#cancel explicitly cancelled}
- * 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}.
- * </ul>
- * Subsequent executions are suppressed. Subsequent calls to
- * {@link Future#isDone isDone()} on the returned future will
- * return {@code true}.
+ * commencement of the next. If any execution of the task
+ * encounters an exception, subsequent executions are suppressed.
+ * Otherwise, the task will only terminate via cancellation or
+ * termination of the executor.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
@@ -167,10 +142,8 @@
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
- * the series of repeated tasks. The future's {@link
- * Future#get() get()} method will never return normally,
- * and will throw an exception upon task cancellation or
- * abnormal termination of a task execution.
+ * the task, and whose {@code get()} method will throw an
+ * exception upon cancellation
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index f9a2000..821342d 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -6,18 +6,12 @@
package java.util.concurrent;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-import java.util.AbstractQueue;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.*;
// BEGIN android-note
// omit class-level docs on setRemoveOnCancelPolicy()
@@ -38,17 +32,17 @@
* submission.
*
* <p>When a submitted task is cancelled before it is run, execution
- * is suppressed. By default, such a cancelled task is not
- * automatically removed from the work queue until its delay elapses.
- * While this enables further inspection and monitoring, it may also
- * cause unbounded retention of cancelled tasks.
+ * is suppressed. By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay
+ * elapses. While this enables further inspection and monitoring, it
+ * may also cause unbounded retention of cancelled tasks.
*
* <p>Successive executions of a periodic task scheduled via
- * {@link #scheduleAtFixedRate scheduleAtFixedRate} or
- * {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
- * do not overlap. While different executions may be performed by
- * different threads, the effects of prior executions
- * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * {@link #scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay} do not overlap. While different
+ * executions may be performed by different threads, the effects of
+ * prior executions <a
+ * href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
* those of subsequent ones.
*
* <p>While this class inherits from {@link ThreadPoolExecutor}, a few
@@ -78,7 +72,7 @@
* {@link FutureTask}. However, this may be modified or replaced using
* subclasses of the form:
*
- * <pre> {@code
+ * <pre> {@code
* public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
*
* static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
@@ -105,10 +99,11 @@
/*
* This class specializes ThreadPoolExecutor implementation by
*
- * 1. Using a custom task type ScheduledFutureTask, even for tasks
- * that don't require scheduling because they are submitted
- * using ExecutorService rather than ScheduledExecutorService
- * methods, which are treated as tasks with a delay of zero.
+ * 1. Using a custom task type, ScheduledFutureTask for
+ * tasks, even those that don't require scheduling (i.e.,
+ * those submitted using ExecutorService execute, not
+ * ScheduledExecutorService methods) which are treated as
+ * delayed tasks with a delay of zero.
*
* 2. Using a custom queue (DelayedWorkQueue), a variant of
* unbounded DelayQueue. The lack of capacity constraint and
@@ -141,7 +136,7 @@
/**
* True if ScheduledFutureTask.cancel should remove from queue.
*/
- volatile boolean removeOnCancel;
+ private volatile boolean removeOnCancel = false;
/**
* Sequence number to break scheduling ties, and in turn to
@@ -149,17 +144,24 @@
*/
private static final AtomicLong sequencer = new AtomicLong();
+ /**
+ * Returns current nanosecond time.
+ */
+ final long now() {
+ return System.nanoTime();
+ }
+
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> {
/** Sequence number to break ties FIFO */
private final long sequenceNumber;
- /** The nanoTime-based time when the task is enabled to execute. */
- private volatile long time;
+ /** The time the task is enabled to execute in nanoTime units */
+ private long time;
/**
- * Period for repeating tasks, in nanoseconds.
+ * Period in nanoseconds for repeating tasks.
* A positive value indicates fixed-rate execution.
* A negative value indicates fixed-delay execution.
* A value of 0 indicates a non-repeating (one-shot) task.
@@ -177,12 +179,11 @@
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Runnable r, V result, long triggerTime,
- long sequenceNumber) {
+ ScheduledFutureTask(Runnable r, V result, long triggerTime) {
super(r, result);
this.time = triggerTime;
this.period = 0;
- this.sequenceNumber = sequenceNumber;
+ this.sequenceNumber = sequencer.getAndIncrement();
}
/**
@@ -190,26 +191,25 @@
* trigger time and period.
*/
ScheduledFutureTask(Runnable r, V result, long triggerTime,
- long period, long sequenceNumber) {
+ long period) {
super(r, result);
this.time = triggerTime;
this.period = period;
- this.sequenceNumber = sequenceNumber;
+ this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Callable<V> callable, long triggerTime,
- long sequenceNumber) {
+ ScheduledFutureTask(Callable<V> callable, long triggerTime) {
super(callable);
this.time = triggerTime;
this.period = 0;
- this.sequenceNumber = sequenceNumber;
+ this.sequenceNumber = sequencer.getAndIncrement();
}
public long getDelay(TimeUnit unit) {
- return unit.convert(time - System.nanoTime(), NANOSECONDS);
+ return unit.convert(time - now(), NANOSECONDS);
}
public int compareTo(Delayed other) {
@@ -252,9 +252,6 @@
}
public boolean cancel(boolean mayInterruptIfRunning) {
- // The racy read of heapIndex below is benign:
- // if heapIndex < 0, then OOTA guarantees that we have surely
- // been removed; else we recheck under lock in remove()
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this);
@@ -269,8 +266,8 @@
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
- super.run();
- else if (super.runAndReset()) {
+ ScheduledFutureTask.super.run();
+ else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
@@ -496,7 +493,7 @@
* Returns the nanoTime-based trigger time of a delayed action.
*/
long triggerTime(long delay) {
- return System.nanoTime() +
+ return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
@@ -528,8 +525,7 @@
throw new NullPointerException();
RunnableScheduledFuture<Void> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
- triggerTime(delay, unit),
- sequencer.getAndIncrement()));
+ triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
@@ -545,8 +541,7 @@
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
- triggerTime(delay, unit),
- sequencer.getAndIncrement()));
+ triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
@@ -562,14 +557,13 @@
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- if (period <= 0L)
+ if (period <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
- unit.toNanos(period),
- sequencer.getAndIncrement());
+ unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
@@ -587,14 +581,13 @@
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- if (delay <= 0L)
+ if (delay <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
- -unit.toNanos(delay),
- sequencer.getAndIncrement());
+ unit.toNanos(-delay));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
@@ -766,8 +759,7 @@
/**
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
- * that were awaiting execution. These tasks are drained (removed)
- * from the task queue upon return from this method.
+ * that were awaiting execution.
*
* <p>This method does not wait for actively executing tasks to
* terminate. Use {@link #awaitTermination awaitTermination} to
@@ -775,7 +767,7 @@
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
- * interrupts tasks via {@link Thread#interrupt}; any task that
+ * cancels tasks via {@link Thread#interrupt}, so any task that
* fails to respond to interrupts may never terminate.
*
* @return list of tasks that never commenced execution.
@@ -783,8 +775,8 @@
* For tasks submitted via one of the {@code schedule}
* methods, the element will be identical to the returned
* {@code ScheduledFuture}. For tasks submitted using
- * {@link #execute execute}, the element will be a
- * zero-delay {@code ScheduledFuture}.
+ * {@link #execute}, the element will be a zero-delay {@code
+ * ScheduledFuture}.
*/
// android-note: Removed "throws SecurityException" doc.
public List<Runnable> shutdownNow() {
@@ -792,16 +784,12 @@
}
/**
- * Returns the task queue used by this executor. Access to the
- * task queue is intended primarily for debugging and monitoring.
- * This queue may be in active use. Retrieving the task queue
- * does not prevent queued tasks from executing.
- *
- * <p>Each element of this queue is a {@link ScheduledFuture}.
+ * Returns the task queue used by this executor.
+ * Each element of this list is a {@link ScheduledFuture}.
* For tasks submitted via one of the {@code schedule} methods, the
* element will be identical to the returned {@code ScheduledFuture}.
- * For tasks submitted using {@link #execute execute}, the element
- * will be a zero-delay {@code ScheduledFuture}.
+ * For tasks submitted using {@link #execute}, the element will be a
+ * zero-delay {@code ScheduledFuture}.
*
* <p>Iteration over this queue is <em>not</em> guaranteed to traverse
* tasks in the order in which they will execute.
@@ -1073,9 +1061,10 @@
lock.lock();
try {
RunnableScheduledFuture<?> first = queue[0];
- return (first == null || first.getDelay(NANOSECONDS) > 0)
- ? null
- : finishPoll(first);
+ if (first == null || first.getDelay(NANOSECONDS) > 0)
+ return null;
+ else
+ return finishPoll(first);
} finally {
lock.unlock();
}
@@ -1091,7 +1080,7 @@
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0L)
+ if (delay <= 0)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null)
@@ -1124,15 +1113,15 @@
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null) {
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
else
nanos = available.awaitNanos(nanos);
} else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0L)
+ if (delay <= 0)
return finishPoll(first);
- if (nanos <= 0L)
+ if (nanos <= 0)
return null;
first = null; // don't retain ref while waiting
if (nanos < delay || leader != null)
@@ -1264,8 +1253,8 @@
*/
private class Itr implements Iterator<Runnable> {
final RunnableScheduledFuture<?>[] array;
- int cursor; // index of next element to return; initially 0
- int lastRet = -1; // index of last element returned; -1 if no such
+ int cursor = 0; // index of next element to return
+ int lastRet = -1; // index of last element, or -1 if no such
Itr(RunnableScheduledFuture<?>[] array) {
this.array = array;
diff --git a/luni/src/main/java/java/util/concurrent/Semaphore.java b/luni/src/main/java/java/util/concurrent/Semaphore.java
index 856b02b..b4b7edd 100644
--- a/luni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/luni/src/main/java/java/util/concurrent/Semaphore.java
@@ -20,7 +20,7 @@
* <p>Semaphores are often used to restrict the number of threads than can
* access some (physical or logical) resource. For example, here is
* a class that uses a semaphore to control access to a pool of items:
- * <pre> {@code
+ * <pre> {@code
* class Pool {
* private static final int MAX_AVAILABLE = 100;
* private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
@@ -113,13 +113,8 @@
*
* <p>This class also provides convenience methods to {@link
* #acquire(int) acquire} and {@link #release(int) release} multiple
- * permits at a time. These methods are generally more efficient and
- * effective than loops. However, they do not establish any preference
- * order. For example, if thread A invokes {@code s.acquire(3}) and
- * thread B invokes {@code s.acquire(2)}, and two permits become
- * available, then there is no guarantee that thread B will obtain
- * them unless its acquire came first and Semaphore {@code s} is in
- * fair mode.
+ * permits at a time. Beware of the increased risk of indefinite
+ * postponement when these methods are used without fairness set true.
*
* <p>Memory consistency effects: Actions in a thread prior to calling
* a "release" method such as {@code release()}
@@ -410,16 +405,14 @@
*
* <p>Acquires the given number of permits, if they are available,
* and returns immediately, reducing the number of available permits
- * by the given amount. This method has the same effect as the
- * loop {@code for (int i = 0; i < permits; ++i) acquire();} except
- * that it atomically acquires the permits all at once:
+ * by the given amount.
*
* <p>If insufficient permits are available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* one of two things happens:
* <ul>
* <li>Some other thread invokes one of the {@link #release() release}
- * methods for this semaphore and the current thread is next to be assigned
+ * methods for this semaphore, the current thread is next to be assigned
* permits and the number of available permits satisfies this request; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
@@ -452,14 +445,12 @@
*
* <p>Acquires the given number of permits, if they are available,
* and returns immediately, reducing the number of available permits
- * by the given amount. This method has the same effect as the
- * loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
- * except that it atomically acquires the permits all at once:
+ * by the given amount.
*
* <p>If insufficient permits are available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* some other thread invokes one of the {@link #release() release}
- * methods for this semaphore and the current thread is next to be assigned
+ * methods for this semaphore, the current thread is next to be assigned
* permits and the number of available permits satisfies this request.
*
* <p>If the current thread is {@linkplain Thread#interrupt interrupted}
@@ -521,7 +512,7 @@
* purposes and lies dormant until one of three things happens:
* <ul>
* <li>Some other thread invokes one of the {@link #release() release}
- * methods for this semaphore and the current thread is next to be assigned
+ * methods for this semaphore, the current thread is next to be assigned
* permits and the number of available permits satisfies this request; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
@@ -568,7 +559,7 @@
*
* <p>Releases the given number of permits, increasing the number of
* available permits by that amount.
- * If any threads are trying to acquire permits, then one thread
+ * If any threads are trying to acquire permits, then one
* is selected and given the permits that were just released.
* If the number of available permits satisfies that thread's request
* then that thread is (re)enabled for thread scheduling purposes;
@@ -652,7 +643,7 @@
* Returns an estimate of the number of threads waiting to acquire.
* The value is only an estimate because the number of threads may
* change dynamically while this method traverses internal data
- * structures. This method is designed for use in monitoring
+ * structures. This method is designed for use in monitoring of the
* system state, not for synchronization control.
*
* @return the estimated number of threads waiting for this lock
diff --git a/luni/src/main/java/java/util/concurrent/SubmissionPublisher.java b/luni/src/main/java/java/util/concurrent/SubmissionPublisher.java
deleted file mode 100644
index 53817e5..0000000
--- a/luni/src/main/java/java/util/concurrent/SubmissionPublisher.java
+++ /dev/null
@@ -1,1603 +0,0 @@
-/*
- * 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.util.ArrayList;
-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;
-
-/**
- * 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>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 Flow.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).
- */
-
- /** The largest possible power of two array size. */
- static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
-
- /** 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 {
- 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 disabled. 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;
- /** If non-null, the exception in closeExceptionally */
- volatile Throwable closedException;
-
- // Parameters for constructing BufferedSubscriptions
- final Executor executor;
- final BiConsumer<? super Flow.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 Flow.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(Flow.Subscriber<? super T> subscriber) {
- if (subscriber == null) throw new NullPointerException();
- BufferedSubscription<T> subscription =
- new BufferedSubscription<T>(subscriber, executor,
- onNextHandler, maxBufferCapacity);
- synchronized (this) {
- 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.isDisabled()) { // 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;
- }
- }
- }
-
- /**
- * 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) {
- if (item == null) throw new NullPointerException();
- int lag = 0;
- boolean complete;
- synchronized (this) {
- complete = closed;
- BufferedSubscription<T> b = clients;
- if (!complete) {
- BufferedSubscription<T> pred = null, r = null, rtail = null;
- while (b != null) {
- BufferedSubscription<T> next = b.next;
- int stat = b.offer(item);
- if (stat < 0) { // disabled
- b.next = null;
- if (pred == null)
- clients = next;
- else
- pred.next = next;
- }
- else {
- if (stat > lag)
- lag = stat;
- else if (stat == 0) { // place on retry list
- b.nextRetry = null;
- if (rtail == null)
- r = b;
- else
- rtail.nextRetry = b;
- rtail = b;
- }
- pred = b;
- }
- b = next;
- }
- while (r != null) {
- BufferedSubscription<T> nextRetry = r.nextRetry;
- r.nextRetry = null;
- int stat = r.submit(item);
- if (stat > lag)
- lag = stat;
- else if (stat < 0 && clients == r)
- clients = r.next; // postpone internal unsubscribes
- r = nextRetry;
- }
- }
- }
- if (complete)
- throw new IllegalStateException("Closed");
- else
- return lag;
- }
-
- /**
- * 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<Flow.Subscriber<? super T>, ? super T> onDrop) {
- return doOffer(0L, item, 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<Flow.Subscriber<? super T>, ? super T> onDrop) {
- return doOffer(unit.toNanos(timeout), item, onDrop);
- }
-
- /** Common implementation for both forms of offer */
- final int doOffer(long nanos, T item,
- BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) {
- if (item == null) throw new NullPointerException();
- int lag = 0, drops = 0;
- boolean complete;
- synchronized (this) {
- complete = closed;
- BufferedSubscription<T> b = clients;
- if (!complete) {
- BufferedSubscription<T> pred = null, r = null, rtail = null;
- while (b != null) {
- BufferedSubscription<T> next = b.next;
- int stat = b.offer(item);
- if (stat < 0) {
- b.next = null;
- if (pred == null)
- clients = next;
- else
- pred.next = next;
- }
- else {
- if (stat > lag)
- lag = stat;
- else if (stat == 0) {
- b.nextRetry = null;
- if (rtail == null)
- r = b;
- else
- rtail.nextRetry = b;
- rtail = b;
- }
- else if (stat > lag)
- lag = stat;
- pred = b;
- }
- b = next;
- }
- while (r != null) {
- BufferedSubscription<T> nextRetry = r.nextRetry;
- r.nextRetry = null;
- int stat = (nanos > 0L) ? r.timedOffer(item, nanos) :
- r.offer(item);
- if (stat == 0 && onDrop != null &&
- onDrop.test(r.subscriber, item))
- stat = r.offer(item);
- if (stat == 0)
- ++drops;
- else if (stat > lag)
- lag = stat;
- else if (stat < 0 && clients == r)
- clients = r.next;
- r = nextRetry;
- }
- }
- }
- if (complete)
- throw new IllegalStateException("Closed");
- else
- return (drops > 0) ? -drops : lag;
- }
-
- /**
- * 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) {
- b = clients;
- clients = 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;
- clients = null;
- closed = true;
- closedException = error;
- }
- 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;
- if (!closed) {
- synchronized (this) {
- for (BufferedSubscription<T> b = clients; b != null;) {
- BufferedSubscription<T> next = b.next;
- if (b.isDisabled()) {
- 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() {
- int count = 0;
- if (!closed) {
- synchronized (this) {
- BufferedSubscription<T> pred = null, next;
- for (BufferedSubscription<T> b = clients; b != null; b = next) {
- next = b.next;
- if (b.isDisabled()) {
- b.next = null;
- if (pred == null)
- clients = next;
- else
- pred.next = next;
- }
- else {
- pred = b;
- ++count;
- }
- }
- }
- }
- return count;
- }
-
- /**
- * 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<Flow.Subscriber<? super T>> getSubscribers() {
- ArrayList<Flow.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.isDisabled()) {
- b.next = null;
- if (pred == null)
- clients = next;
- else
- pred.next = next;
- }
- else
- subs.add(b.subscriber);
- }
- }
- 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(Flow.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.isDisabled()) {
- 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 */
- private static final class ConsumerSubscriber<T>
- implements Flow.Subscriber<T> {
- final CompletableFuture<Void> status;
- final Consumer<? super T> consumer;
- Flow.Subscription subscription;
- ConsumerSubscriber(CompletableFuture<Void> status,
- Consumer<? super T> consumer) {
- this.status = status; this.consumer = consumer;
- }
- public final void onSubscribe(Flow.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 {
- 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 bounded (ring) buffer with integrated control to start a
- * consumer task whenever items are available. The buffer
- * algorithm is similar to one used inside ForkJoinPool (see its
- * internal documentation for details) specialized for the case of
- * at most one concurrent producer and consumer, and power of two
- * buffer sizes. This allows methods to operate without locks even
- * while supporting resizing, blocking, task-triggering, and
- * garbage-free buffers (nulling out elements when consumed),
- * although supporting these does impose a bit of overhead
- * compared to plain fixed-size ring buffers.
- *
- * The publisher guarantees a single producer via its lock. We
- * ensure in this class that there is at most one consumer. The
- * request and cancel methods must be fully thread-safe but are
- * coded to exploit the most common case in which they are only
- * called by consumers (usually within onNext).
- *
- * Execution control is managed using the ACTIVE ctl bit. We
- * ensure that a task is active when consumable items (and
- * usually, SUBSCRIBE, ERROR or COMPLETE signals) are present and
- * there is demand (unfilled requests). This is complicated on
- * the creation side by the possibility of exceptions when trying
- * to execute tasks. These eventually force DISABLED state, but
- * sometimes not directly. On the task side, termination (clearing
- * ACTIVE) that would otherwise race with producers or request()
- * calls uses the CONSUME keep-alive bit to force a recheck.
- *
- * The ctl field also manages run state. When DISABLED, no further
- * updates are possible. Disabling may be preceded by setting
- * ERROR or COMPLETE (or both -- ERROR has precedence), in which
- * case the associated Subscriber methods are invoked, possibly
- * synchronously if there is no active consumer task (including
- * cases where execute() failed). 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 "waiter" field. Producers set
- * the field before trying to block, but must then recheck (via
- * offer) before parking. Signalling then just unparks and clears
- * waiter field. If the producer and consumer are both in the same
- * ForkJoinPool, or consumers are running in commonPool, the
- * producer attempts to help run consumer tasks that it forked
- * before blocking. To avoid potential cycles, only one level of
- * helping is currently supported.
- *
- * This class uses @Contended and heuristic field declaration
- * ordering to reduce false-sharing-based memory contention among
- * instances of BufferedSubscription, but it does not currently
- * attempt to avoid memory contention among buffers. This field
- * and element packing can hurt performance especially when each
- * publisher has only one client operating at a high rate.
- * Addressing this may require allocating substantially more space
- * than users expect.
- */
- @SuppressWarnings("serial")
- @jdk.internal.vm.annotation.Contended
- private static final class BufferedSubscription<T>
- implements Flow.Subscription, ForkJoinPool.ManagedBlocker {
- // Order-sensitive field declarations
- long timeout; // > 0 if timed wait
- volatile long demand; // # unfilled requests
- int maxCapacity; // reduced on OOME
- int putStat; // offer result for ManagedBlocker
- int helpDepth; // nested helping depth (at most 1)
- volatile int ctl; // atomic run state flags
- volatile int head; // next position to take
- int tail; // next position to put
- Object[] array; // buffer: null if disabled
- Flow.Subscriber<? super T> subscriber; // null if disabled
- Executor executor; // null if disabled
- BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> onNextHandler;
- volatile Throwable pendingError; // holds until onError issued
- volatile Thread waiter; // blocked producer thread
- T putItem; // for offer within ManagedBlocker
- BufferedSubscription<T> next; // used only by publisher
- BufferedSubscription<T> nextRetry; // used only by publisher
-
- // ctl values
- static final int ACTIVE = 0x01; // consumer task active
- static final int CONSUME = 0x02; // keep-alive for consumer task
- static final int DISABLED = 0x04; // final state
- static final int ERROR = 0x08; // signal onError then disable
- static final int SUBSCRIBE = 0x10; // signal onSubscribe
- static final int COMPLETE = 0x20; // signal onComplete when done
-
- static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
-
- /**
- * Initial buffer capacity used when maxBufferCapacity is
- * greater. Must be a power of two.
- */
- static final int DEFAULT_INITIAL_CAP = 32;
-
- BufferedSubscription(Flow.Subscriber<? super T> subscriber,
- Executor executor,
- BiConsumer<? super Flow.Subscriber<? super T>,
- ? super Throwable> onNextHandler,
- int maxBufferCapacity) {
- this.subscriber = subscriber;
- this.executor = executor;
- this.onNextHandler = onNextHandler;
- this.maxCapacity = maxBufferCapacity;
- this.array = new Object[maxBufferCapacity < DEFAULT_INITIAL_CAP ?
- (maxBufferCapacity < 2 ? // at least 2 slots
- 2 : maxBufferCapacity) :
- DEFAULT_INITIAL_CAP];
- }
-
- final boolean isDisabled() {
- return ctl == DISABLED;
- }
-
- /**
- * Returns estimated number of buffered items, or -1 if
- * disabled.
- */
- final int estimateLag() {
- int n;
- return (ctl == DISABLED) ? -1 : ((n = tail - head) > 0) ? n : 0;
- }
-
- /**
- * Tries to add item and start consumer task if necessary.
- * @return -1 if disabled, 0 if dropped, else estimated lag
- */
- final int offer(T item) {
- int h = head, t = tail, cap, size, stat;
- Object[] a = array;
- if (a != null && (cap = a.length) > 0 && cap >= (size = t + 1 - h)) {
- a[(cap - 1) & t] = item; // relaxed writes OK
- tail = t + 1;
- stat = size;
- }
- else
- stat = growAndAdd(a, item);
- return (stat > 0 &&
- (ctl & (ACTIVE | CONSUME)) != (ACTIVE | CONSUME)) ?
- startOnOffer(stat) : stat;
- }
-
- /**
- * Tries to create or expand buffer, then adds item if possible.
- */
- private int growAndAdd(Object[] a, T item) {
- boolean alloc;
- int cap, stat;
- if ((ctl & (ERROR | DISABLED)) != 0) {
- cap = 0;
- stat = -1;
- alloc = false;
- }
- else if (a == null || (cap = a.length) <= 0) {
- cap = 0;
- stat = 1;
- alloc = true;
- }
- else {
- U.fullFence(); // recheck
- int h = head, t = tail, size = t + 1 - h;
- if (cap >= size) {
- a[(cap - 1) & t] = item;
- tail = t + 1;
- stat = size;
- alloc = false;
- }
- else if (cap >= maxCapacity) {
- stat = 0; // cannot grow
- alloc = false;
- }
- else {
- stat = cap + 1;
- alloc = true;
- }
- }
- if (alloc) {
- int newCap = (cap > 0) ? cap << 1 : 1;
- if (newCap <= cap)
- stat = 0;
- else {
- Object[] newArray = null;
- try {
- newArray = new Object[newCap];
- } catch (Throwable ex) { // try to cope with OOME
- }
- if (newArray == null) {
- if (cap > 0)
- maxCapacity = cap; // avoid continuous failure
- stat = 0;
- }
- else {
- array = newArray;
- int t = tail;
- int newMask = newCap - 1;
- if (a != null && cap > 0) {
- int mask = cap - 1;
- for (int j = head; j != t; ++j) {
- long k = ((long)(j & mask) << ASHIFT) + ABASE;
- Object x = U.getObjectVolatile(a, k);
- if (x != null && // races with consumer
- U.compareAndSwapObject(a, k, x, null))
- newArray[j & newMask] = x;
- }
- }
- newArray[t & newMask] = item;
- tail = t + 1;
- }
- }
- }
- return stat;
- }
-
- /**
- * Spins/helps/blocks while offer returns 0. Called only if
- * initial offer return 0.
- */
- final int submit(T item) {
- int stat; Executor e; ForkJoinWorkerThread w;
- if ((stat = offer(item)) == 0 && helpDepth == 0 &&
- ((e = executor) instanceof ForkJoinPool)) {
- helpDepth = 1;
- Thread thread = Thread.currentThread();
- if ((thread instanceof ForkJoinWorkerThread) &&
- ((w = (ForkJoinWorkerThread)thread)).getPool() == e)
- stat = internalHelpConsume(w.workQueue, item);
- else if (e == ForkJoinPool.commonPool())
- stat = externalHelpConsume
- (ForkJoinPool.commonSubmitterQueue(), item);
- helpDepth = 0;
- }
- if (stat == 0 && (stat = offer(item)) == 0) {
- putItem = item;
- timeout = 0L;
- try {
- ForkJoinPool.managedBlock(this);
- } catch (InterruptedException ie) {
- timeout = INTERRUPTED;
- }
- stat = putStat;
- if (timeout < 0L)
- Thread.currentThread().interrupt();
- }
- return stat;
- }
-
- /**
- * Tries helping for FJ submitter.
- */
- private int internalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
- int stat = 0;
- if (w != null) {
- ForkJoinTask<?> t;
- while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
- if ((stat = offer(item)) != 0 || !w.tryUnpush(t))
- break;
- ((ConsumerTask<?>)t).consumer.consume();
- }
- }
- return stat;
- }
-
- /**
- * Tries helping for non-FJ submitter.
- */
- private int externalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
- int stat = 0;
- if (w != null) {
- ForkJoinTask<?> t;
- while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
- if ((stat = offer(item)) != 0 || !w.trySharedUnpush(t))
- break;
- ((ConsumerTask<?>)t).consumer.consume();
- }
- }
- return stat;
- }
-
- /**
- * Timeout version; similar to submit.
- */
- final int timedOffer(T item, long nanos) {
- int stat; Executor e;
- if ((stat = offer(item)) == 0 && helpDepth == 0 &&
- ((e = executor) instanceof ForkJoinPool)) {
- Thread thread = Thread.currentThread();
- if (((thread instanceof ForkJoinWorkerThread) &&
- ((ForkJoinWorkerThread)thread).getPool() == e) ||
- e == ForkJoinPool.commonPool()) {
- helpDepth = 1;
- ForkJoinTask<?> t;
- long deadline = System.nanoTime() + nanos;
- while ((t = ForkJoinTask.peekNextLocalTask()) != null &&
- (t instanceof ConsumerTask)) {
- if ((stat = offer(item)) != 0 ||
- (nanos = deadline - System.nanoTime()) <= 0L ||
- !t.tryUnfork())
- break;
- ((ConsumerTask<?>)t).consumer.consume();
- }
- helpDepth = 0;
- }
- }
- if (stat == 0 && (stat = offer(item)) == 0 &&
- (timeout = nanos) > 0L) {
- putItem = item;
- try {
- ForkJoinPool.managedBlock(this);
- } catch (InterruptedException ie) {
- timeout = INTERRUPTED;
- }
- stat = putStat;
- if (timeout < 0L)
- Thread.currentThread().interrupt();
- }
- return stat;
- }
-
- /**
- * Tries to start consumer task after offer.
- * @return -1 if now disabled, else argument
- */
- private int startOnOffer(int stat) {
- for (;;) {
- Executor e; int c;
- if ((c = ctl) == DISABLED || (e = executor) == null) {
- stat = -1;
- break;
- }
- else if ((c & ACTIVE) != 0) { // ensure keep-alive
- if ((c & CONSUME) != 0 ||
- U.compareAndSwapInt(this, CTL, c,
- c | CONSUME))
- break;
- }
- else if (demand == 0L || tail == head)
- break;
- else if (U.compareAndSwapInt(this, CTL, c,
- c | (ACTIVE | CONSUME))) {
- try {
- e.execute(new ConsumerTask<T>(this));
- break;
- } catch (RuntimeException | Error ex) { // back out
- do {} while (((c = ctl) & DISABLED) == 0 &&
- (c & ACTIVE) != 0 &&
- !U.compareAndSwapInt(this, CTL, c,
- c & ~ACTIVE));
- throw ex;
- }
- }
- }
- return stat;
- }
-
- private void signalWaiter(Thread w) {
- waiter = null;
- LockSupport.unpark(w); // release producer
- }
-
- /**
- * Nulls out most fields, mainly to avoid garbage retention
- * until publisher unsubscribes, but also to help cleanly stop
- * upon error by nulling required components.
- */
- private void detach() {
- Thread w = waiter;
- executor = null;
- subscriber = null;
- pendingError = null;
- signalWaiter(w);
- }
-
- /**
- * Issues error signal, asynchronously if a task is running,
- * else synchronously.
- */
- final void onError(Throwable ex) {
- for (int c;;) {
- if (((c = ctl) & (ERROR | DISABLED)) != 0)
- break;
- else if ((c & ACTIVE) != 0) {
- pendingError = ex;
- if (U.compareAndSwapInt(this, CTL, c, c | ERROR))
- break; // cause consumer task to exit
- }
- else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
- Flow.Subscriber<? super T> s = subscriber;
- if (s != null && ex != null) {
- try {
- s.onError(ex);
- } catch (Throwable ignore) {
- }
- }
- detach();
- break;
- }
- }
- }
-
- /**
- * Tries to start consumer task upon a signal or request;
- * disables on failure.
- */
- private void startOrDisable() {
- Executor e;
- if ((e = executor) != null) { // skip if already disabled
- try {
- e.execute(new ConsumerTask<T>(this));
- } catch (Throwable ex) { // back out and force signal
- for (int c;;) {
- if ((c = ctl) == DISABLED || (c & ACTIVE) == 0)
- break;
- if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) {
- onError(ex);
- break;
- }
- }
- }
- }
- }
-
- final void onComplete() {
- for (int c;;) {
- if ((c = ctl) == DISABLED)
- break;
- if (U.compareAndSwapInt(this, CTL, c,
- c | (ACTIVE | CONSUME | COMPLETE))) {
- if ((c & ACTIVE) == 0)
- startOrDisable();
- break;
- }
- }
- }
-
- final void onSubscribe() {
- for (int c;;) {
- if ((c = ctl) == DISABLED)
- break;
- if (U.compareAndSwapInt(this, CTL, c,
- c | (ACTIVE | CONSUME | SUBSCRIBE))) {
- if ((c & ACTIVE) == 0)
- startOrDisable();
- break;
- }
- }
- }
-
- /**
- * Causes consumer task to exit if active (without reporting
- * onError unless there is already a pending error), and
- * disables.
- */
- public void cancel() {
- for (int c;;) {
- if ((c = ctl) == DISABLED)
- break;
- else if ((c & ACTIVE) != 0) {
- if (U.compareAndSwapInt(this, CTL, c,
- c | (CONSUME | ERROR)))
- break;
- }
- else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
- detach();
- break;
- }
- }
- }
-
- /**
- * Adds to demand and possibly starts task.
- */
- public void request(long n) {
- if (n > 0L) {
- for (;;) {
- long prev = demand, d;
- if ((d = prev + n) < prev) // saturate
- d = Long.MAX_VALUE;
- if (U.compareAndSwapLong(this, DEMAND, prev, d)) {
- for (int c, h;;) {
- if ((c = ctl) == DISABLED)
- break;
- else if ((c & ACTIVE) != 0) {
- if ((c & CONSUME) != 0 ||
- U.compareAndSwapInt(this, CTL, c,
- c | CONSUME))
- break;
- }
- else if ((h = head) != tail) {
- if (U.compareAndSwapInt(this, CTL, c,
- c | (ACTIVE|CONSUME))) {
- startOrDisable();
- break;
- }
- }
- else if (head == h && tail == h)
- break; // else stale
- if (demand == 0L)
- break;
- }
- break;
- }
- }
- }
- else if (n < 0L)
- onError(new IllegalArgumentException(
- "negative subscription request"));
- }
-
- public final boolean isReleasable() { // for ManagedBlocker
- T item = putItem;
- if (item != null) {
- if ((putStat = offer(item)) == 0)
- return false;
- putItem = null;
- }
- return true;
- }
-
- public final boolean block() { // for ManagedBlocker
- T item = putItem;
- if (item != null) {
- putItem = null;
- long nanos = timeout;
- long deadline = (nanos > 0L) ? System.nanoTime() + nanos : 0L;
- while ((putStat = offer(item)) == 0) {
- if (Thread.interrupted()) {
- timeout = INTERRUPTED;
- if (nanos > 0L)
- break;
- }
- else if (nanos > 0L &&
- (nanos = deadline - System.nanoTime()) <= 0L)
- break;
- else if (waiter == null)
- waiter = Thread.currentThread();
- else {
- if (nanos > 0L)
- LockSupport.parkNanos(this, nanos);
- else
- LockSupport.park(this);
- waiter = null;
- }
- }
- }
- waiter = null;
- return true;
- }
-
- /**
- * Consumer loop, called from ConsumerTask, or indirectly
- * when helping during submit.
- */
- final void consume() {
- Flow.Subscriber<? super T> s;
- int h = head;
- if ((s = subscriber) != null) { // else disabled
- for (;;) {
- long d = demand;
- int c; Object[] a; int n; long i; Object x; Thread w;
- if (((c = ctl) & (ERROR | SUBSCRIBE | DISABLED)) != 0) {
- if (!checkControl(s, c))
- break;
- }
- else if ((a = array) == null || h == tail ||
- (n = a.length) == 0 ||
- (x = U.getObjectVolatile
- (a, (i = ((long)((n - 1) & h) << ASHIFT) + ABASE)))
- == null) {
- if (!checkEmpty(s, c))
- break;
- }
- else if (d == 0L) {
- if (!checkDemand(c))
- break;
- }
- else if (((c & CONSUME) != 0 ||
- U.compareAndSwapInt(this, CTL, c, c | CONSUME)) &&
- U.compareAndSwapObject(a, i, x, null)) {
- U.putOrderedInt(this, HEAD, ++h);
- U.getAndAddLong(this, DEMAND, -1L);
- if ((w = waiter) != null)
- signalWaiter(w);
- try {
- @SuppressWarnings("unchecked") T y = (T) x;
- s.onNext(y);
- } catch (Throwable ex) {
- handleOnNext(s, ex);
- }
- }
- }
- }
- }
-
- /**
- * Responds to control events in consume().
- */
- private boolean checkControl(Flow.Subscriber<? super T> s, int c) {
- boolean stat = true;
- if ((c & ERROR) != 0) {
- Throwable ex = pendingError;
- ctl = DISABLED; // no need for CAS
- if (ex != null) { // null if errorless cancel
- try {
- if (s != null)
- s.onError(ex);
- } catch (Throwable ignore) {
- }
- }
- }
- else if ((c & SUBSCRIBE) != 0) {
- if (U.compareAndSwapInt(this, CTL, c, c & ~SUBSCRIBE)) {
- try {
- if (s != null)
- s.onSubscribe(this);
- } catch (Throwable ex) {
- onError(ex);
- }
- }
- }
- else {
- detach();
- stat = false;
- }
- return stat;
- }
-
- /**
- * Responds to apparent emptiness in consume().
- */
- private boolean checkEmpty(Flow.Subscriber<? super T> s, int c) {
- boolean stat = true;
- if (head == tail) {
- if ((c & CONSUME) != 0)
- U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
- else if ((c & COMPLETE) != 0) {
- if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
- try {
- if (s != null)
- s.onComplete();
- } catch (Throwable ignore) {
- }
- }
- }
- else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
- stat = false;
- }
- return stat;
- }
-
- /**
- * Responds to apparent zero demand in consume().
- */
- private boolean checkDemand(int c) {
- boolean stat = true;
- if (demand == 0L) {
- if ((c & CONSUME) != 0)
- U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
- else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
- stat = false;
- }
- return stat;
- }
-
- /**
- * Processes exception in Subscriber.onNext.
- */
- private void handleOnNext(Flow.Subscriber<? super T> s, Throwable ex) {
- BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> h;
- if ((h = onNextHandler) != null) {
- try {
- h.accept(s, ex);
- } catch (Throwable ignore) {
- }
- }
- onError(ex);
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long CTL;
- private static final long TAIL;
- private static final long HEAD;
- private static final long DEMAND;
- private static final int ABASE;
- private static final int ASHIFT;
-
- static {
- try {
- CTL = U.objectFieldOffset
- (BufferedSubscription.class.getDeclaredField("ctl"));
- TAIL = U.objectFieldOffset
- (BufferedSubscription.class.getDeclaredField("tail"));
- HEAD = U.objectFieldOffset
- (BufferedSubscription.class.getDeclaredField("head"));
- DEMAND = U.objectFieldOffset
- (BufferedSubscription.class.getDeclaredField("demand"));
-
- ABASE = U.arrayBaseOffset(Object[].class);
- int scale = U.arrayIndexScale(Object[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("data type 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;
- }
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
index a46f672..69452af 100644
--- a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -7,14 +7,9 @@
package java.util.concurrent;
-import java.util.AbstractQueue;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.Spliterators;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.*;
// BEGIN android-note
// removed link to collections framework docs
@@ -54,7 +49,7 @@
*
* @since 1.5
* @author Doug Lea and Bill Scherer and Michael Scott
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -157,6 +152,9 @@
abstract E transfer(E e, boolean timed, long nanos);
}
+ /** The number of CPUs, for spin control */
+ static final int NCPUS = Runtime.getRuntime().availableProcessors();
+
/**
* The number of times to spin before blocking in timed waits.
* The value is empirically derived -- it works well across a
@@ -164,21 +162,20 @@
* seems not to vary with number of CPUs (beyond 2) so is just
* a constant.
*/
- static final int MAX_TIMED_SPINS =
- (Runtime.getRuntime().availableProcessors() < 2) ? 0 : 32;
+ static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
/**
* The number of times to spin before blocking in untimed waits.
* This is greater than timed value because untimed waits spin
* faster since they don't need to check times on each spin.
*/
- static final int MAX_UNTIMED_SPINS = MAX_TIMED_SPINS * 16;
+ static final int maxUntimedSpins = maxTimedSpins * 16;
/**
* The number of nanoseconds for which it is faster to spin
* rather than to use timed park. A rough estimate suffices.
*/
- static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+ static final long spinForTimeoutThreshold = 1000L;
/** Dual stack */
static final class TransferStack<E> extends Transferer<E> {
@@ -218,7 +215,7 @@
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
/**
@@ -231,7 +228,7 @@
*/
boolean tryMatch(SNode s) {
if (match == null &&
- U.compareAndSwapObject(this, MATCH, null, s)) {
+ UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@@ -246,7 +243,7 @@
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
- U.compareAndSwapObject(this, MATCH, null, this);
+ UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
}
boolean isCancelled() {
@@ -254,17 +251,19 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long MATCH;
- private static final long NEXT;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long matchOffset;
+ private static final long nextOffset;
static {
try {
- MATCH = U.objectFieldOffset
- (SNode.class.getDeclaredField("match"));
- NEXT = U.objectFieldOffset
- (SNode.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = SNode.class;
+ matchOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("match"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -275,7 +274,7 @@
boolean casHead(SNode h, SNode nh) {
return h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh);
+ UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
}
/**
@@ -324,7 +323,7 @@
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // empty or same-mode
- if (timed && nanos <= 0L) { // can't wait
+ if (timed && nanos <= 0) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
@@ -406,9 +405,8 @@
*/
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
- int spins = shouldSpin(s)
- ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
- : 0;
+ int spins = (shouldSpin(s) ?
+ (timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) {
if (w.isInterrupted())
s.tryCancel();
@@ -423,12 +421,12 @@
}
}
if (spins > 0)
- spins = shouldSpin(s) ? (spins - 1) : 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)
LockSupport.park(this);
- else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+ else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
@@ -480,13 +478,15 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferStack.class.getDeclaredField("head"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = TransferStack.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -517,19 +517,19 @@
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
- U.compareAndSwapObject(this, ITEM, cmp, val);
+ UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
- U.compareAndSwapObject(this, ITEM, cmp, this);
+ UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
}
boolean isCancelled() {
@@ -546,17 +546,19 @@
}
// 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 sun.misc.Unsafe UNSAFE;
+ private static final long itemOffset;
+ private static final long nextOffset;
static {
try {
- ITEM = U.objectFieldOffset
- (QNode.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (QNode.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = QNode.class;
+ itemOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("item"));
+ nextOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("next"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -585,7 +587,7 @@
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh))
+ UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
h.next = h; // forget old next
}
@@ -594,7 +596,7 @@
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
- U.compareAndSwapObject(this, TAIL, t, nt);
+ UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
}
/**
@@ -602,7 +604,7 @@
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
- U.compareAndSwapObject(this, CLEANME, cmp, val);
+ UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
}
/**
@@ -652,7 +654,7 @@
advanceTail(t, tn);
continue;
}
- if (timed && nanos <= 0L) // can't wait
+ if (timed && nanos <= 0) // can't wait
return null;
if (s == null)
s = new QNode(e, isData);
@@ -707,9 +709,8 @@
/* Same idea as TransferStack.awaitFulfill */
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
- int spins = (head.next == s)
- ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
- : 0;
+ int spins = ((head.next == s) ?
+ (timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) {
if (w.isInterrupted())
s.tryCancel(e);
@@ -729,7 +730,7 @@
s.waiter = w;
else if (!timed)
LockSupport.park(this);
- else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+ else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
@@ -788,19 +789,21 @@
}
}
- 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;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long headOffset;
+ private static final long tailOffset;
+ private static final long cleanMeOffset;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("tail"));
- CLEANME = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("cleanMe"));
- } catch (ReflectiveOperationException e) {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class<?> k = TransferQueue.class;
+ headOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("head"));
+ tailOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("tail"));
+ cleanMeOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("cleanMe"));
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -1031,19 +1034,19 @@
*
* @return an empty iterator
*/
+ @SuppressWarnings("unchecked")
public Iterator<E> iterator() {
- return Collections.emptyIterator();
+ return (Iterator<E>) EmptyIterator.EMPTY_ITERATOR;
}
- /**
- * Returns an empty spliterator in which calls to
- * {@link java.util.Spliterator#trySplit()} always return {@code null}.
- *
- * @return an empty spliterator
- * @since 1.8
- */
- public Spliterator<E> spliterator() {
- return Spliterators.emptySpliterator();
+ // Replicated from a previous version of Collections
+ private static class EmptyIterator<E> implements Iterator<E> {
+ static final EmptyIterator<Object> EMPTY_ITERATOR
+ = new EmptyIterator<Object>();
+
+ public boolean hasNext() { return false; }
+ public E next() { throw new NoSuchElementException(); }
+ public void remove() { throw new IllegalStateException(); }
}
/**
@@ -1069,14 +1072,6 @@
}
/**
- * Always returns {@code "[]"}.
- * @return {@code "[]"}
- */
- public String toString() {
- return "[]";
- }
-
- /**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
@@ -1136,8 +1131,6 @@
/**
* Saves this queue to a stream (that is, serializes it).
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
@@ -1157,10 +1150,6 @@
/**
* 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1171,6 +1160,19 @@
transferer = new TransferStack<E>();
}
+ // Unsafe mechanics
+ static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
+ String field, Class<?> klazz) {
+ try {
+ return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
+ } catch (NoSuchFieldException e) {
+ // Convert Exception to corresponding Error
+ NoSuchFieldError error = new NoSuchFieldError(field);
+ error.initCause(e);
+ throw error;
+ }
+ }
+
static {
// Reduce the risk of rare disastrous classloading in first call to
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
diff --git a/luni/src/main/java/java/util/concurrent/ThreadFactory.java b/luni/src/main/java/java/util/concurrent/ThreadFactory.java
index fdedea3..d1a4eb6 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadFactory.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadFactory.java
@@ -13,7 +13,7 @@
*
* <p>
* The simplest implementation of this interface is just:
- * <pre> {@code
+ * <pre> {@code
* class SimpleThreadFactory implements ThreadFactory {
* public Thread newThread(Runnable r) {
* return new Thread(r);
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index 8c65bde..b007af2 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -6,19 +6,7 @@
package java.util.concurrent;
-import java.io.ObjectStreamField;
import java.util.Random;
-import java.util.Spliterator;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.DoubleConsumer;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-// TODO(streams):
-// import java.util.stream.DoubleStream;
-// import java.util.stream.IntStream;
-// import java.util.stream.LongStream;
-// import java.util.stream.StreamSupport;
/**
* A random number generator isolated to the current thread. Like the
@@ -41,98 +29,50 @@
* <p>This class also provides additional commonly used bounded random
* generation methods.
*
- * <p>Instances of {@code ThreadLocalRandom} are not cryptographically
- * secure. Consider instead using {@link java.security.SecureRandom}
- * in security-sensitive applications. Additionally,
- * default-constructed instances do not use a cryptographically random
- * seed unless the {@linkplain System#getProperty system property}
- * {@code java.util.secureRandomSeed} is set to {@code true}.
- *
* @since 1.7
* @author Doug Lea
*/
public class ThreadLocalRandom extends Random {
- /*
- * This class implements the java.util.Random API (and subclasses
- * Random) using a single static instance that accesses random
- * number state held in class Thread (primarily, field
- * threadLocalRandomSeed). In doing so, it also provides a home
- * for managing package-private utilities that rely on exactly the
- * same state as needed to maintain the ThreadLocalRandom
- * instances. We leverage the need for an initialization flag
- * field to also use it as a "probe" -- a self-adjusting thread
- * hash used for contention avoidance, as well as a secondary
- * simpler (xorShift) random seed that is conservatively used to
- * avoid otherwise surprising users by hijacking the
- * 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 though this class subclasses java.util.Random, it uses the
- * same basic algorithm as java.util.SplittableRandom. (See its
- * internal documentation for explanations, which are not repeated
- * here.) Because ThreadLocalRandoms are not splittable
- * though, we use only a single 64bit gamma.
- *
- * Because this class is in a different package than class Thread,
- * field access methods use Unsafe to bypass access control rules.
- * To conform to the requirements of the Random superclass
- * constructor, the common static ThreadLocalRandom maintains an
- * "initialized" field for the sake of rejecting user calls to
- * setSeed while still allowing a call from constructor. Note
- * that serialization is completely unnecessary because there is
- * only a static singleton. But we generate a serial form
- * containing "rnd" and "initialized" fields to ensure
- * compatibility across versions.
- *
- * Implementations of non-core methods are mostly the same as in
- * SplittableRandom, that were in part derived from a previous
- * version of this class.
- *
- * The nextLocalGaussian ThreadLocal supports the very rarely used
- * nextGaussian method by providing a holder for the second of a
- * pair of them. As is true for the base class version of this
- * method, this time/space tradeoff is probably never worthwhile,
- * but we provide identical statistical properties.
- */
-
- private static long mix64(long z) {
- z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
- z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
- return z ^ (z >>> 33);
- }
-
- private static int mix32(long z) {
- z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
- return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
- }
+ // same constants as Random, but must be redeclared because private
+ private static final long multiplier = 0x5DEECE66DL;
+ private static final long addend = 0xBL;
+ private static final long mask = (1L << 48) - 1;
/**
- * Field used only during singleton initialization.
- * True when constructor completes.
+ * The random seed. We can't use super.seed.
+ */
+ private long rnd;
+
+ /**
+ * Initialization flag to permit calls to setSeed to succeed only
+ * while executing the Random constructor. We can't allow others
+ * since it would cause setting seed in one part of a program to
+ * unintentionally impact other usages by the thread.
*/
boolean initialized;
- /** Constructor used only for static singleton */
- private ThreadLocalRandom() {
- initialized = true; // false during super() call
- }
+ // Padding to help avoid memory contention among seed updates in
+ // different TLRs in the common case that they are located near
+ // each other.
+ private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
/**
- * Initialize Thread fields for the current thread. Called only
- * when Thread.threadLocalRandomProbe is zero, indicating that a
- * thread local seed value needs to be generated. Note that even
- * though the initialization is purely thread-local, we need to
- * rely on (static) atomic generators to initialize the values.
+ * The actual ThreadLocal
*/
- static final void localInit() {
- int p = probeGenerator.addAndGet(PROBE_INCREMENT);
- int probe = (p == 0) ? 1 : p; // skip 0
- long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
- Thread t = Thread.currentThread();
- U.putLong(t, SEED, seed);
- U.putInt(t, PROBE, probe);
+ private static final ThreadLocal<ThreadLocalRandom> localRandom =
+ new ThreadLocal<ThreadLocalRandom>() {
+ protected ThreadLocalRandom initialValue() {
+ return new ThreadLocalRandom();
+ }
+ };
+
+
+ /**
+ * Constructor called only by localRandom.initialValue.
+ */
+ ThreadLocalRandom() {
+ super();
+ initialized = true;
}
/**
@@ -141,9 +81,7 @@
* @return the current thread's {@code ThreadLocalRandom}
*/
public static ThreadLocalRandom current() {
- if (U.getInt(Thread.currentThread(), PROBE) == 0)
- localInit();
- return instance;
+ return localRandom.get();
}
/**
@@ -153,894 +91,107 @@
* @throws UnsupportedOperationException always
*/
public void setSeed(long seed) {
- // only allow call from super() constructor
if (initialized)
throw new UnsupportedOperationException();
+ rnd = (seed ^ multiplier) & mask;
}
- final long nextSeed() {
- Thread t; long r; // read and update per-thread seed
- U.putLong(t = Thread.currentThread(), SEED,
- r = U.getLong(t, SEED) + GAMMA);
- return r;
- }
-
- // We must define this, but never use it.
protected int next(int bits) {
- return (int)(mix64(nextSeed()) >>> (64 - bits));
+ rnd = (rnd * multiplier + addend) & mask;
+ return (int) (rnd >>> (48-bits));
}
/**
- * The form of nextLong used by LongStream Spliterators. If
- * origin is greater than bound, acts as unbounded form of
- * nextLong, else as bounded form.
+ * Returns a pseudorandom, uniformly distributed value between the
+ * given least value (inclusive) and bound (exclusive).
*
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final long internalNextLong(long origin, long bound) {
- long r = mix64(nextSeed());
- if (origin < bound) {
- long n = bound - origin, m = n - 1;
- if ((n & m) == 0L) // power of two
- r = (r & m) + origin;
- else if (n > 0L) { // reject over-represented candidates
- for (long u = r >>> 1; // ensure nonnegative
- u + m - (r = u % n) < 0L; // rejection check
- u = mix64(nextSeed()) >>> 1) // retry
- ;
- r += origin;
- }
- else { // range not representable as long
- while (r < origin || r >= bound)
- r = mix64(nextSeed());
- }
- }
- return r;
- }
-
- /**
- * The form of nextInt used by IntStream Spliterators.
- * Exactly the same as long version, except for types.
- *
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final int internalNextInt(int origin, int bound) {
- int r = mix32(nextSeed());
- if (origin < bound) {
- int n = bound - origin, m = n - 1;
- if ((n & m) == 0)
- r = (r & m) + origin;
- else if (n > 0) {
- for (int u = r >>> 1;
- u + m - (r = u % n) < 0;
- u = mix32(nextSeed()) >>> 1)
- ;
- r += origin;
- }
- else {
- while (r < origin || r >= bound)
- r = mix32(nextSeed());
- }
- }
- return r;
- }
-
- /**
- * The form of nextDouble used by DoubleStream Spliterators.
- *
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final double internalNextDouble(double origin, double bound) {
- double r = (nextLong() >>> 11) * DOUBLE_UNIT;
- if (origin < bound) {
- r = r * (bound - origin) + origin;
- if (r >= bound) // correct for rounding
- r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
- }
- return r;
- }
-
- /**
- * Returns a pseudorandom {@code int} value.
- *
- * @return a pseudorandom {@code int} value
- */
- public int nextInt() {
- return mix32(nextSeed());
- }
-
- /**
- * Returns a pseudorandom {@code int} value between zero (inclusive)
- * and the specified bound (exclusive).
- *
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code int} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public int nextInt(int bound) {
- if (bound <= 0)
- throw new IllegalArgumentException(BAD_BOUND);
- int r = mix32(nextSeed());
- int m = bound - 1;
- if ((bound & m) == 0) // power of two
- r &= m;
- else { // reject over-represented candidates
- for (int u = r >>> 1;
- u + m - (r = u % bound) < 0;
- u = mix32(nextSeed()) >>> 1)
- ;
- }
- return r;
- }
-
- /**
- * Returns a pseudorandom {@code int} value between the specified
- * origin (inclusive) and the specified bound (exclusive).
- *
- * @param origin the least value returned
+ * @param least the least value returned
* @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code int} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
+ * @return the next value
+ * @throws IllegalArgumentException if least greater than or equal
+ * to bound
*/
- public int nextInt(int origin, int bound) {
- if (origin >= bound)
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextInt(origin, bound);
+ public int nextInt(int least, int bound) {
+ if (least >= bound)
+ throw new IllegalArgumentException();
+ return nextInt(bound - least) + least;
}
/**
- * Returns a pseudorandom {@code long} value.
+ * Returns a pseudorandom, uniformly distributed value
+ * between 0 (inclusive) and the specified value (exclusive).
*
- * @return a pseudorandom {@code long} value
+ * @param n the bound on the random number to be returned. Must be
+ * positive.
+ * @return the next value
+ * @throws IllegalArgumentException if n is not positive
*/
- public long nextLong() {
- return mix64(nextSeed());
- }
-
- /**
- * Returns a pseudorandom {@code long} value between zero (inclusive)
- * and the specified bound (exclusive).
- *
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code long} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public long nextLong(long bound) {
- if (bound <= 0)
- throw new IllegalArgumentException(BAD_BOUND);
- long r = mix64(nextSeed());
- long m = bound - 1;
- if ((bound & m) == 0L) // power of two
- r &= m;
- else { // reject over-represented candidates
- for (long u = r >>> 1;
- u + m - (r = u % bound) < 0L;
- u = mix64(nextSeed()) >>> 1)
- ;
+ public long nextLong(long n) {
+ if (n <= 0)
+ throw new IllegalArgumentException("n must be positive");
+ // Divide n by two until small enough for nextInt. On each
+ // iteration (at most 31 of them but usually much less),
+ // randomly choose both whether to include high bit in result
+ // (offset) and whether to continue with the lower vs upper
+ // half (which makes a difference only if odd).
+ long offset = 0;
+ while (n >= Integer.MAX_VALUE) {
+ int bits = next(2);
+ long half = n >>> 1;
+ long nextn = ((bits & 2) == 0) ? half : n - half;
+ if ((bits & 1) == 0)
+ offset += n - nextn;
+ n = nextn;
}
- return r;
+ return offset + nextInt((int) n);
}
/**
- * Returns a pseudorandom {@code long} value between the specified
- * origin (inclusive) and the specified bound (exclusive).
+ * Returns a pseudorandom, uniformly distributed value between the
+ * given least value (inclusive) and bound (exclusive).
*
- * @param origin the least value returned
+ * @param least the least value returned
* @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code long} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
+ * @return the next value
+ * @throws IllegalArgumentException if least greater than or equal
+ * to bound
*/
- public long nextLong(long origin, long bound) {
- if (origin >= bound)
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextLong(origin, bound);
+ public long nextLong(long least, long bound) {
+ if (least >= bound)
+ throw new IllegalArgumentException();
+ return nextLong(bound - least) + least;
}
/**
- * Returns a pseudorandom {@code double} value between zero
- * (inclusive) and one (exclusive).
+ * Returns a pseudorandom, uniformly distributed {@code double} value
+ * between 0 (inclusive) and the specified value (exclusive).
*
- * @return a pseudorandom {@code double} value between zero
- * (inclusive) and one (exclusive)
+ * @param n the bound on the random number to be returned. Must be
+ * positive.
+ * @return the next value
+ * @throws IllegalArgumentException if n is not positive
*/
- public double nextDouble() {
- return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
+ public double nextDouble(double n) {
+ if (!(n > 0))
+ throw new IllegalArgumentException("n must be positive");
+ return nextDouble() * n;
}
/**
- * Returns a pseudorandom {@code double} value between 0.0
- * (inclusive) and the specified bound (exclusive).
+ * Returns a pseudorandom, uniformly distributed value between the
+ * given least value (inclusive) and bound (exclusive).
*
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code double} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public double nextDouble(double bound) {
- if (!(bound > 0.0))
- throw new IllegalArgumentException(BAD_BOUND);
- double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
- return (result < bound) ? result : // correct for rounding
- Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
- }
-
- /**
- * Returns a pseudorandom {@code double} value between the specified
- * origin (inclusive) and bound (exclusive).
- *
- * @param origin the least value returned
+ * @param least the least value returned
* @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code double} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
+ * @return the next value
+ * @throws IllegalArgumentException if least greater than or equal
+ * to bound
*/
- public double nextDouble(double origin, double bound) {
- if (!(origin < bound))
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextDouble(origin, bound);
+ public double nextDouble(double least, double bound) {
+ if (least >= bound)
+ throw new IllegalArgumentException();
+ return nextDouble() * (bound - least) + least;
}
- /**
- * Returns a pseudorandom {@code boolean} value.
- *
- * @return a pseudorandom {@code boolean} value
- */
- public boolean nextBoolean() {
- return mix32(nextSeed()) < 0;
- }
-
- /**
- * Returns a pseudorandom {@code float} value between zero
- * (inclusive) and one (exclusive).
- *
- * @return a pseudorandom {@code float} value between zero
- * (inclusive) and one (exclusive)
- */
- public float nextFloat() {
- return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
- }
-
- public double nextGaussian() {
- // Use nextLocalGaussian instead of nextGaussian field
- Double d = nextLocalGaussian.get();
- if (d != null) {
- nextLocalGaussian.set(null);
- return d.doubleValue();
- }
- double v1, v2, s;
- do {
- v1 = 2 * nextDouble() - 1; // between -1 and 1
- v2 = 2 * nextDouble() - 1; // between -1 and 1
- s = v1 * v1 + v2 * v2;
- } while (s >= 1 || s == 0);
- double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
- nextLocalGaussian.set(new Double(v2 * multiplier));
- return v1 * multiplier;
- }
-
- // stream methods, coded in a way intended to better isolate for
- // maintenance purposes the small differences across forms.
-
- // TODO(streams):
- // /**
- // * Returns a stream producing the given {@code streamSize} number of
- // * pseudorandom {@code int} values.
- // *
- // * @param streamSize the number of values to generate
- // * @return a stream of pseudorandom {@code int} values
- // * @throws IllegalArgumentException if {@code streamSize} is
- // * less than zero
- // * @since 1.8
- // */
- // public IntStream ints(long streamSize) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // return StreamSupport.intStream
- // (new RandomIntsSpliterator
- // (0L, streamSize, Integer.MAX_VALUE, 0),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code int}
- // * values.
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * ints(Long.MAX_VALUE)}.
- // *
- // * @return a stream of pseudorandom {@code int} values
- // * @since 1.8
- // */
- // public IntStream ints() {
- // return StreamSupport.intStream
- // (new RandomIntsSpliterator
- // (0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
- // false);
- // }
-
- // /**
- // * Returns a stream producing the given {@code streamSize} number
- // * of pseudorandom {@code int} values, each conforming to the given
- // * origin (inclusive) and bound (exclusive).
- // *
- // * @param streamSize the number of values to generate
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @return a stream of pseudorandom {@code int} values,
- // * each with the given origin (inclusive) and bound (exclusive)
- // * @throws IllegalArgumentException if {@code streamSize} is
- // * less than zero, or {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public IntStream ints(long streamSize, int randomNumberOrigin,
- // int randomNumberBound) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // if (randomNumberOrigin >= randomNumberBound)
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.intStream
- // (new RandomIntsSpliterator
- // (0L, streamSize, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code
- // * int} values, each conforming to the given origin (inclusive) and bound
- // * (exclusive).
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- // *
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @return a stream of pseudorandom {@code int} values,
- // * each with the given origin (inclusive) and bound (exclusive)
- // * @throws IllegalArgumentException if {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
- // if (randomNumberOrigin >= randomNumberBound)
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.intStream
- // (new RandomIntsSpliterator
- // (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- // /**
- // * Returns a stream producing the given {@code streamSize} number of
- // * pseudorandom {@code long} values.
- // *
- // * @param streamSize the number of values to generate
- // * @return a stream of pseudorandom {@code long} values
- // * @throws IllegalArgumentException if {@code streamSize} is
- // * less than zero
- // * @since 1.8
- // */
- // public LongStream longs(long streamSize) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // return StreamSupport.longStream
- // (new RandomLongsSpliterator
- // (0L, streamSize, Long.MAX_VALUE, 0L),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code long}
- // * values.
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * longs(Long.MAX_VALUE)}.
- // *
- // * @return a stream of pseudorandom {@code long} values
- // * @since 1.8
- // */
- // public LongStream longs() {
- // return StreamSupport.longStream
- // (new RandomLongsSpliterator
- // (0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
- // false);
- // }
-
- // /**
- // * Returns a stream producing the given {@code streamSize} number of
- // * pseudorandom {@code long}, each conforming to the given origin
- // * (inclusive) and bound (exclusive).
- // *
- // * @param streamSize the number of values to generate
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @return a stream of pseudorandom {@code long} values,
- // * each with the given origin (inclusive) and bound (exclusive)
- // * @throws IllegalArgumentException if {@code streamSize} is
- // * less than zero, or {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public LongStream longs(long streamSize, long randomNumberOrigin,
- // long randomNumberBound) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // if (randomNumberOrigin >= randomNumberBound)
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.longStream
- // (new RandomLongsSpliterator
- // (0L, streamSize, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code
- // * long} values, each conforming to the given origin (inclusive) and bound
- // * (exclusive).
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- // *
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @return a stream of pseudorandom {@code long} values,
- // * each with the given origin (inclusive) and bound (exclusive)
- // * @throws IllegalArgumentException if {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
- // if (randomNumberOrigin >= randomNumberBound)
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.longStream
- // (new RandomLongsSpliterator
- // (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- // /**
- // * Returns a stream producing the given {@code streamSize} number of
- // * pseudorandom {@code double} values, each between zero
- // * (inclusive) and one (exclusive).
- // *
- // * @param streamSize the number of values to generate
- // * @return a stream of {@code double} values
- // * @throws IllegalArgumentException if {@code streamSize} is
- // * less than zero
- // * @since 1.8
- // */
- // public DoubleStream doubles(long streamSize) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // return StreamSupport.doubleStream
- // (new RandomDoublesSpliterator
- // (0L, streamSize, Double.MAX_VALUE, 0.0),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code
- // * double} values, each between zero (inclusive) and one
- // * (exclusive).
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * doubles(Long.MAX_VALUE)}.
- // *
- // * @return a stream of pseudorandom {@code double} values
- // * @since 1.8
- // */
- // public DoubleStream doubles() {
- // return StreamSupport.doubleStream
- // (new RandomDoublesSpliterator
- // (0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
- // false);
- // }
-
- // /**
- // * Returns a stream producing the given {@code streamSize} number of
- // * pseudorandom {@code double} values, each conforming to the given origin
- // * (inclusive) and bound (exclusive).
- // *
- // * @param streamSize the number of values to generate
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @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
- // * @throws IllegalArgumentException if {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public DoubleStream doubles(long streamSize, double randomNumberOrigin,
- // double randomNumberBound) {
- // if (streamSize < 0L)
- // throw new IllegalArgumentException(BAD_SIZE);
- // if (!(randomNumberOrigin < randomNumberBound))
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.doubleStream
- // (new RandomDoublesSpliterator
- // (0L, streamSize, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- // /**
- // * Returns an effectively unlimited stream of pseudorandom {@code
- // * double} values, each conforming to the given origin (inclusive) and bound
- // * (exclusive).
- // *
- // * @implNote This method is implemented to be equivalent to {@code
- // * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- // *
- // * @param randomNumberOrigin the origin (inclusive) of each random value
- // * @param randomNumberBound the bound (exclusive) of each random value
- // * @return a stream of pseudorandom {@code double} values,
- // * each with the given origin (inclusive) and bound (exclusive)
- // * @throws IllegalArgumentException if {@code randomNumberOrigin}
- // * is greater than or equal to {@code randomNumberBound}
- // * @since 1.8
- // */
- // public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
- // if (!(randomNumberOrigin < randomNumberBound))
- // throw new IllegalArgumentException(BAD_RANGE);
- // return StreamSupport.doubleStream
- // (new RandomDoublesSpliterator
- // (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- // false);
- // }
-
- /**
- * Spliterator for int streams. We multiplex the four int
- * versions into one class by treating a bound less than origin as
- * unbounded, and also by treating "infinite" as equivalent to
- * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
- * approach. The long and double versions of this class are
- * identical except for types.
- */
- private static final class RandomIntsSpliterator
- implements Spliterator.OfInt {
- long index;
- final long fence;
- final int origin;
- final int bound;
- RandomIntsSpliterator(long index, long fence,
- int origin, int bound) {
- this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomIntsSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomIntsSpliterator(i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(IntConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(IntConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- int o = origin, b = bound;
- ThreadLocalRandom rng = ThreadLocalRandom.current();
- do {
- consumer.accept(rng.internalNextInt(o, b));
- } while (++i < f);
- }
- }
- }
-
- /**
- * Spliterator for long streams.
- */
- private static final class RandomLongsSpliterator
- implements Spliterator.OfLong {
- long index;
- final long fence;
- final long origin;
- final long bound;
- RandomLongsSpliterator(long index, long fence,
- long origin, long bound) {
- this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomLongsSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomLongsSpliterator(i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(LongConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(LongConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- long o = origin, b = bound;
- ThreadLocalRandom rng = ThreadLocalRandom.current();
- do {
- consumer.accept(rng.internalNextLong(o, b));
- } while (++i < f);
- }
- }
-
- }
-
- /**
- * Spliterator for double streams.
- */
- private static final class RandomDoublesSpliterator
- implements Spliterator.OfDouble {
- long index;
- final long fence;
- final double origin;
- final double bound;
- RandomDoublesSpliterator(long index, long fence,
- double origin, double bound) {
- this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomDoublesSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomDoublesSpliterator(i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(DoubleConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(DoubleConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- double o = origin, b = bound;
- ThreadLocalRandom rng = ThreadLocalRandom.current();
- do {
- consumer.accept(rng.internalNextDouble(o, b));
- } while (++i < f);
- }
- }
- }
-
-
- // Within-package utilities
-
- /*
- * Descriptions of the usages of the methods below can be found in
- * the classes that use them. Briefly, a thread's "probe" value is
- * a non-zero hash code that (probably) does not collide with
- * other existing threads with respect to any power of two
- * collision space. When it does collide, it is pseudo-randomly
- * adjusted (using a Marsaglia XorShift). The nextSecondarySeed
- * method is used in the same contexts as ThreadLocalRandom, but
- * only for transient usages such as random adaptive spin/block
- * sequences for which a cheap RNG suffices and for which it could
- * in principle disrupt user-visible statistical properties of the
- * main ThreadLocalRandom if we were to use it.
- *
- * Note: Because of package-protection issues, versions of some
- * these methods also appear in some subpackage classes.
- */
-
- /**
- * Returns the probe value for the current thread without forcing
- * initialization. Note that invoking ThreadLocalRandom.current()
- * can be used to force initialization on zero return.
- */
- static final int getProbe() {
- return U.getInt(Thread.currentThread(), PROBE);
- }
-
- /**
- * Pseudo-randomly advances and records the given probe value for the
- * given thread.
- */
- static final int advanceProbe(int probe) {
- probe ^= probe << 13; // xorshift
- probe ^= probe >>> 17;
- probe ^= probe << 5;
- U.putInt(Thread.currentThread(), PROBE, probe);
- return probe;
- }
-
- /**
- * Returns the pseudo-randomly initialized or updated secondary seed.
- */
- static final int nextSecondarySeed() {
- int r;
- Thread t = Thread.currentThread();
- if ((r = U.getInt(t, SECONDARY)) != 0) {
- r ^= r << 13; // xorshift
- r ^= r >>> 17;
- r ^= r << 5;
- }
- else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
- r = 1; // avoid zero
- U.putInt(t, SECONDARY, r);
- return r;
- }
-
- // Serialization support
-
private static final long serialVersionUID = -5851777807851030925L;
-
- /**
- * @serialField rnd long
- * seed for random computations
- * @serialField initialized boolean
- * always true
- */
- private static final ObjectStreamField[] serialPersistentFields = {
- new ObjectStreamField("rnd", long.class),
- new ObjectStreamField("initialized", boolean.class),
- };
-
- /**
- * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
- */
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
-
- java.io.ObjectOutputStream.PutField fields = s.putFields();
- fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
- fields.put("initialized", true);
- s.writeFields();
- }
-
- /**
- * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
- * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
- */
- private Object readResolve() {
- return current();
- }
-
- // Static initialization
-
- /**
- * The seed increment.
- */
- private static final long GAMMA = 0x9e3779b97f4a7c15L;
-
- /**
- * The increment for generating probe values.
- */
- private static final int PROBE_INCREMENT = 0x9e3779b9;
-
- /**
- * The increment of seeder per new instance.
- */
- private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
-
- // 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)
-
- // IllegalArgumentException messages
- static final String BAD_BOUND = "bound must be positive";
- static final String BAD_RANGE = "bound must be greater than origin";
- static final String BAD_SIZE = "size must be non-negative";
-
- // Unsafe mechanics
- 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 =
- new ThreadLocal<>();
-
- /** Generates per-thread initialization/probe field */
- private static final AtomicInteger probeGenerator = new AtomicInteger();
-
- /** The common ThreadLocalRandom */
- static final ThreadLocalRandom instance = new ThreadLocalRandom();
-
- /**
- * The next seed for default constructors.
- */
- private static final AtomicLong seeder
- = new AtomicLong(mix64(System.currentTimeMillis()) ^
- mix64(System.nanoTime()));
-
- // at end of <clinit> to survive static initialization circularity
- static {
- 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)
- s = (s << 8) | ((long)seedBytes[i] & 0xffL);
- seeder.set(s);
- }
- }
}
diff --git a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index e601b6a..c484920 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -6,15 +6,11 @@
package java.util.concurrent;
-import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.*;
// BEGIN android-note
// removed security manager docs
@@ -49,8 +45,7 @@
*
* <dt>Core and maximum pool sizes</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A {@code ThreadPoolExecutor} will automatically adjust the
+ * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
* pool size (see {@link #getPoolSize})
* according to the bounds set by
* corePoolSize (see {@link #getCorePoolSize}) and
@@ -72,8 +67,7 @@
*
* <dt>On-demand construction</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * By default, even core threads are initially created and
+ * <dd>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
@@ -81,8 +75,7 @@
*
* <dt>Creating new threads</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New threads are created using a {@link ThreadFactory}. If not
+ * <dd>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
@@ -90,17 +83,11 @@
* alter the thread's name, thread group, priority, daemon status,
* etc. If a {@code ThreadFactory} fails to create a thread when asked
* by returning null from {@code newThread}, the executor will
- * continue, but might not be able to execute any tasks. Threads
- * should possess the "modifyThread" {@code RuntimePermission}. If
- * worker threads or other threads using the pool do not possess this
- * permission, service may be degraded: configuration changes may not
- * take effect in a timely manner, and a shutdown pool may remain in a
- * state in which termination is possible but not completed.</dd>
+ * continue, but might not be able to execute any tasks.</dd>
*
* <dt>Keep-alive times</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * If the pool currently has more than corePoolSize threads,
+ * <dd>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
@@ -110,37 +97,36 @@
* TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link
* TimeUnit#NANOSECONDS} effectively disables idle threads from ever
* terminating prior to shut down. By default, the keep-alive policy
- * applies only when there are more than corePoolSize threads, but
+ * applies only when there are more than corePoolSize threads. But
* method {@link #allowCoreThreadTimeOut(boolean)} can be used to
* apply this time-out policy to core threads as well, so long as the
* keepAliveTime value is non-zero. </dd>
*
* <dt>Queuing</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Any {@link BlockingQueue} may be used to transfer and hold
+ * <dd>Any {@link BlockingQueue} may be used to transfer and hold
* submitted tasks. The use of this queue interacts with pool sizing:
*
* <ul>
*
- * <li>If fewer than corePoolSize threads are running, the Executor
+ * <li> If fewer than corePoolSize threads are running, the Executor
* always prefers adding a new thread
- * rather than queuing.
+ * rather than queuing.</li>
*
- * <li>If corePoolSize or more threads are running, the Executor
+ * <li> If corePoolSize or more threads are running, the Executor
* always prefers queuing a request rather than adding a new
- * thread.
+ * thread.</li>
*
- * <li>If a request cannot be queued, a new thread is created unless
+ * <li> If a request cannot be queued, a new thread is created unless
* this would exceed maximumPoolSize, in which case, the task will be
- * rejected.
+ * rejected.</li>
*
* </ul>
*
* There are three general strategies for queuing:
* <ol>
*
- * <li><em> Direct handoffs.</em> A good default choice for a work
+ * <li> <em> Direct handoffs.</em> A good default choice for a work
* queue is a {@link SynchronousQueue} that hands off tasks to threads
* without otherwise holding them. Here, an attempt to queue a task
* will fail if no threads are immediately available to run it, so a
@@ -149,7 +135,7 @@
* Direct handoffs generally require unbounded maximumPoolSizes to
* avoid rejection of new submitted tasks. This in turn admits the
* possibility of unbounded thread growth when commands continue to
- * arrive on average faster than they can be processed.
+ * arrive on average faster than they can be processed. </li>
*
* <li><em> Unbounded queues.</em> Using an unbounded queue (for
* example a {@link LinkedBlockingQueue} without a predefined
@@ -162,7 +148,7 @@
* While this style of queuing can be useful in smoothing out
* transient bursts of requests, it admits the possibility of
* unbounded work queue growth when commands continue to arrive on
- * average faster than they can be processed.
+ * average faster than they can be processed. </li>
*
* <li><em>Bounded queues.</em> A bounded queue (for example, an
* {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
@@ -175,7 +161,7 @@
* time for more threads than you otherwise allow. Use of small queues
* generally requires larger pool sizes, which keeps CPUs busier but
* may encounter unacceptable scheduling overhead, which also
- * decreases throughput.
+ * decreases throughput. </li>
*
* </ol>
*
@@ -183,8 +169,7 @@
*
* <dt>Rejected tasks</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New tasks submitted in method {@link #execute(Runnable)} will be
+ * <dd>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
@@ -195,22 +180,22 @@
*
* <ol>
*
- * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
* handler throws a runtime {@link RejectedExecutionException} upon
- * rejection.
+ * rejection. </li>
*
- * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
+ * <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
* that invokes {@code execute} itself runs the task. This provides a
* simple feedback control mechanism that will slow down the rate that
- * new tasks are submitted.
+ * new tasks are submitted. </li>
*
- * <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
- * cannot be executed is simply dropped.
+ * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
+ * cannot be executed is simply dropped. </li>
*
* <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
* executor is not shut down, the task at the head of the work queue
* is dropped, and then execution is retried (which can fail again,
- * causing this to be repeated.)
+ * causing this to be repeated.) </li>
*
* </ol>
*
@@ -221,8 +206,7 @@
*
* <dt>Hook methods</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * This class provides {@code protected} overridable
+ * <dd>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
@@ -232,14 +216,12 @@
* any special processing that needs to be done once the Executor has
* fully terminated.
*
- * <p>If hook, callback, or BlockingQueue methods throw exceptions,
- * internal worker threads may in turn fail, abruptly terminate, and
- * possibly be replaced.</dd>
+ * <p>If hook or callback methods throw exceptions, internal worker
+ * threads may in turn fail and abruptly terminate.</dd>
*
* <dt>Queue maintenance</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Method {@link #getQueue()} allows access to the work queue
+ * <dd>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
@@ -248,8 +230,7 @@
*
* <dt>Finalization</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A pool that is no longer referenced in a program <em>AND</em>
+ * <dd>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
@@ -263,7 +244,7 @@
* override one or more of the protected hook methods. For example,
* here is a subclass that adds a simple pause/resume feature:
*
- * <pre> {@code
+ * <pre> {@code
* class PausableThreadPoolExecutor extends ThreadPoolExecutor {
* private boolean isPaused;
* private ReentrantLock pauseLock = new ReentrantLock();
@@ -452,10 +433,10 @@
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
- private final HashSet<Worker> workers = new HashSet<>();
+ private final HashSet<Worker> workers = new HashSet<Worker>();
/**
- * Wait condition to support awaitTermination.
+ * Wait condition to support awaitTermination
*/
private final Condition termination = mainLock.newCondition();
@@ -531,7 +512,7 @@
private volatile int maximumPoolSize;
/**
- * The default rejected execution handler.
+ * The default rejected execution handler
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
@@ -658,7 +639,6 @@
* (but not TIDYING or TERMINATED -- use tryTerminate for that)
*/
private void advanceRunState(int targetState) {
- // assert targetState == SHUTDOWN || targetState == STOP;
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
@@ -841,7 +821,7 @@
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
- ArrayList<Runnable> taskList = new ArrayList<>();
+ ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
@@ -1396,7 +1376,7 @@
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
- * interrupts tasks via {@link Thread#interrupt}; any task that
+ * cancels tasks via {@link Thread#interrupt}, so any task that
* fails to respond to interrupts may never terminate.
*/
// android-note: Removed @throws SecurityException
@@ -1446,12 +1426,13 @@
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
- while (!runStateAtLeast(ctl.get(), TERMINATED)) {
- if (nanos <= 0L)
+ for (;;) {
+ if (runStateAtLeast(ctl.get(), TERMINATED))
+ return true;
+ if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
- return true;
} finally {
mainLock.unlock();
}
@@ -1520,12 +1501,10 @@
*
* @param corePoolSize the new core size
* @throws IllegalArgumentException if {@code corePoolSize < 0}
- * or {@code corePoolSize} is greater than the {@linkplain
- * #getMaximumPoolSize() maximum pool size}
* @see #getCorePoolSize
*/
public void setCorePoolSize(int corePoolSize) {
- if (corePoolSize < 0 || maximumPoolSize < corePoolSize)
+ if (corePoolSize < 0)
throw new IllegalArgumentException();
int delta = corePoolSize - this.corePoolSize;
this.corePoolSize = corePoolSize;
@@ -1668,13 +1647,11 @@
}
/**
- * Sets the thread keep-alive time, which is the amount of time
- * that threads may remain idle before being terminated.
- * Threads that wait this amount of time without processing a
- * task will be terminated if there are more than the core
- * number of threads currently in the pool, or if this pool
- * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
- * This overrides any value set in the constructor.
+ * Sets the time limit for which threads may remain idle before
+ * being terminated. If there are more than the core number of
+ * threads currently in the pool, after waiting this amount of
+ * time without processing a task, excess threads will be
+ * terminated. This overrides any value set in the constructor.
*
* @param time the time to wait. A time value of zero will cause
* excess threads to terminate immediately after executing tasks.
@@ -1697,11 +1674,8 @@
/**
* Returns the thread keep-alive time, which is the amount of time
- * that threads may remain idle before being terminated.
- * Threads that wait this amount of time without processing a
- * task will be terminated if there are more than the core
- * number of threads currently in the pool, or if this pool
- * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+ * that threads in excess of the core pool size may remain
+ * idle before being terminated.
*
* @param unit the desired time unit of the result
* @return the time limit
@@ -1732,8 +1706,8 @@
*
* <p>This method may be useful as one part of a cancellation
* scheme. It may fail to remove tasks that have been converted
- * into other forms before being placed on the internal queue.
- * For example, a task entered using {@code submit} might be
+ * into other forms before being placed on the internal queue. For
+ * example, a task entered using {@code submit} might be
* converted into a form that maintains {@code Future} status.
* However, in such cases, method {@link #purge} may be used to
* remove those Futures that have been cancelled.
@@ -1905,12 +1879,11 @@
mainLock.unlock();
}
int c = ctl.get();
- String runState =
- runStateLessThan(c, SHUTDOWN) ? "Running" :
- runStateAtLeast(c, TERMINATED) ? "Terminated" :
- "Shutting down";
+ String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
+ (runStateAtLeast(c, TERMINATED) ? "Terminated" :
+ "Shutting down"));
return super.toString() +
- "[" + runState +
+ "[" + rs +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
@@ -1957,23 +1930,20 @@
* as in this sample subclass that prints either the direct cause
* or the underlying exception if a task has been aborted:
*
- * <pre> {@code
+ * <pre> {@code
* class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
- * if (t == null
- * && r instanceof Future<?>
- * && ((Future<?>)r).isDone()) {
+ * if (t == null && r instanceof Future<?>) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
- * t = ce;
+ * t = ce;
* } catch (ExecutionException ee) {
- * t = ee.getCause();
+ * t = ee.getCause();
* } catch (InterruptedException ie) {
- * // ignore/reset
- * Thread.currentThread().interrupt();
+ * Thread.currentThread().interrupt(); // ignore/reset
* }
* }
* if (t != null)
diff --git a/luni/src/main/java/java/util/concurrent/TimeUnit.java b/luni/src/main/java/java/util/concurrent/TimeUnit.java
index fff02d8..8e6a5f7 100644
--- a/luni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/luni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -6,12 +6,6 @@
package java.util.concurrent;
-import java.util.Objects;
-
-// BEGIN android-note
-// removed java 9 ChronoUnit related code
-// END android-note
-
/**
* A {@code TimeUnit} represents time durations at a given unit of
* granularity and provides utility methods to convert across units,
@@ -29,12 +23,12 @@
* the following code will timeout in 50 milliseconds if the {@link
* java.util.concurrent.locks.Lock lock} is not available:
*
- * <pre> {@code
+ * <pre> {@code
* Lock lock = ...;
* if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
*
* while this code will timeout in 50 seconds:
- * <pre> {@code
+ * <pre> {@code
* Lock lock = ...;
* if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
*
@@ -47,7 +41,7 @@
*/
public enum TimeUnit {
/**
- * Time unit representing one thousandth of a microsecond.
+ * Time unit representing one thousandth of a microsecond
*/
NANOSECONDS {
public long toNanos(long d) { return d; }
@@ -62,7 +56,7 @@
},
/**
- * Time unit representing one thousandth of a millisecond.
+ * Time unit representing one thousandth of a millisecond
*/
MICROSECONDS {
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
@@ -77,7 +71,7 @@
},
/**
- * Time unit representing one thousandth of a second.
+ * Time unit representing one thousandth of a second
*/
MILLISECONDS {
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
@@ -92,7 +86,7 @@
},
/**
- * Time unit representing one second.
+ * Time unit representing one second
*/
SECONDS {
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
@@ -107,7 +101,7 @@
},
/**
- * Time unit representing sixty seconds.
+ * Time unit representing sixty seconds
* @since 1.6
*/
MINUTES {
@@ -123,7 +117,7 @@
},
/**
- * Time unit representing sixty minutes.
+ * Time unit representing sixty minutes
* @since 1.6
*/
HOURS {
@@ -139,7 +133,7 @@
},
/**
- * Time unit representing twenty four hours.
+ * Time unit representing twenty four hours
* @since 1.6
*/
DAYS {
@@ -170,7 +164,7 @@
* This has a short name to make above code more readable.
*/
static long x(long d, long m, long over) {
- if (d > +over) return Long.MAX_VALUE;
+ if (d > over) return Long.MAX_VALUE;
if (d < -over) return Long.MIN_VALUE;
return d * m;
}
@@ -306,7 +300,7 @@
* method (see {@link BlockingQueue#poll BlockingQueue.poll})
* using:
*
- * <pre> {@code
+ * <pre> {@code
* public synchronized Object poll(long timeout, TimeUnit unit)
* throws InterruptedException {
* while (empty) {
@@ -366,4 +360,5 @@
Thread.sleep(ms, ns);
}
}
+
}
diff --git a/luni/src/main/java/java/util/concurrent/TransferQueue.java b/luni/src/main/java/java/util/concurrent/TransferQueue.java
index d4166b5..4c2be6f 100644
--- a/luni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -34,7 +34,7 @@
*
* @since 1.7
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public interface TransferQueue<E> extends BlockingQueue<E> {
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
index 01e4b07..f51e6af 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
@@ -6,6 +6,8 @@
package java.util.concurrent.atomic;
+import sun.misc.Unsafe;
+
/**
* A {@code boolean} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for
@@ -19,17 +21,15 @@
*/
public class AtomicBoolean implements java.io.Serializable {
private static final long serialVersionUID = 4654671469794556979L;
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ // setup to use Unsafe.compareAndSwapInt for updates
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long valueOffset;
static {
try {
- VALUE = U.objectFieldOffset
+ valueOffset = unsafe.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ } catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
@@ -64,13 +64,13 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
+ int e = expect ? 1 : 0;
+ int u = update ? 1 : 0;
+ return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
/**
@@ -83,12 +83,12 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean weakCompareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
+ int e = expect ? 1 : 0;
+ int u = update ? 1 : 0;
+ return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
/**
@@ -107,7 +107,8 @@
* @since 1.6
*/
public final void lazySet(boolean newValue) {
- U.putOrderedInt(this, VALUE, (newValue ? 1 : 0));
+ int v = newValue ? 1 : 0;
+ unsafe.putOrderedInt(this, valueOffset, v);
}
/**
@@ -117,11 +118,11 @@
* @return the previous value
*/
public final boolean getAndSet(boolean newValue) {
- boolean prev;
- do {
- prev = get();
- } while (!compareAndSet(prev, newValue));
- return prev;
+ for (;;) {
+ boolean current = get();
+ if (compareAndSet(current, newValue))
+ return current;
+ }
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
index 849fd8a..8a15298 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
@@ -6,8 +6,7 @@
package java.util.concurrent.atomic;
-import java.util.function.IntBinaryOperator;
-import java.util.function.IntUnaryOperator;
+import sun.misc.Unsafe;
/**
* An {@code int} value that may be updated atomically. See the
@@ -21,20 +20,19 @@
*
* @since 1.5
* @author Doug Lea
- */
+*/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ // setup to use Unsafe.compareAndSwapInt for updates
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long valueOffset;
static {
try {
- VALUE = U.objectFieldOffset
+ valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ } catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
@@ -79,7 +77,7 @@
* @since 1.6
*/
public final void lazySet(int newValue) {
- U.putOrderedInt(this, VALUE, newValue);
+ unsafe.putOrderedInt(this, valueOffset, newValue);
}
/**
@@ -89,7 +87,11 @@
* @return the previous value
*/
public final int getAndSet(int newValue) {
- return U.getAndSetInt(this, VALUE, newValue);
+ for (;;) {
+ int current = get();
+ if (compareAndSet(current, newValue))
+ return current;
+ }
}
/**
@@ -98,11 +100,11 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
- return U.compareAndSwapInt(this, VALUE, expect, update);
+ return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
@@ -115,10 +117,10 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(int expect, int update) {
- return U.compareAndSwapInt(this, VALUE, expect, update);
+ return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
@@ -127,7 +129,12 @@
* @return the previous value
*/
public final int getAndIncrement() {
- return U.getAndAddInt(this, VALUE, 1);
+ for (;;) {
+ int current = get();
+ int next = current + 1;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -136,7 +143,12 @@
* @return the previous value
*/
public final int getAndDecrement() {
- return U.getAndAddInt(this, VALUE, -1);
+ for (;;) {
+ int current = get();
+ int next = current - 1;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -146,7 +158,12 @@
* @return the previous value
*/
public final int getAndAdd(int delta) {
- return U.getAndAddInt(this, VALUE, delta);
+ for (;;) {
+ int current = get();
+ int next = current + delta;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -155,7 +172,12 @@
* @return the updated value
*/
public final int incrementAndGet() {
- return U.getAndAddInt(this, VALUE, 1) + 1;
+ for (;;) {
+ int current = get();
+ int next = current + 1;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -164,7 +186,12 @@
* @return the updated value
*/
public final int decrementAndGet() {
- return U.getAndAddInt(this, VALUE, -1) - 1;
+ for (;;) {
+ int current = get();
+ int next = current - 1;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -174,93 +201,12 @@
* @return the updated value
*/
public final int addAndGet(int delta) {
- return U.getAndAddInt(this, VALUE, delta) + delta;
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final int getAndUpdate(IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final int updateAndGet(IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(prev, next));
- return next;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final int getAndAccumulate(int x,
- IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final int accumulateAndGet(int x,
- IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ for (;;) {
+ int current = get();
+ int next = current + delta;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -273,7 +219,6 @@
/**
* Returns the value of this {@code AtomicInteger} as an {@code int}.
- * Equivalent to {@link #get()}.
*/
public int intValue() {
return get();
@@ -282,7 +227,6 @@
/**
* Returns the value of this {@code AtomicInteger} as a {@code long}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
*/
public long longValue() {
return (long)get();
@@ -291,7 +235,6 @@
/**
* Returns the value of this {@code AtomicInteger} as a {@code float}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
return (float)get();
@@ -300,7 +243,6 @@
/**
* Returns the value of this {@code AtomicInteger} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
index 7597e53..fd492d1 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -6,8 +6,7 @@
package java.util.concurrent.atomic;
-import java.util.function.IntBinaryOperator;
-import java.util.function.IntUnaryOperator;
+import sun.misc.Unsafe;
/**
* An {@code int} array in which elements may be updated atomically.
@@ -20,17 +19,16 @@
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final int base = unsafe.arrayBaseOffset(int[].class);
+ private static final int shift;
private final int[] array;
static {
- ABASE = U.arrayBaseOffset(int[].class);
- int scale = U.arrayIndexScale(int[].class);
+ int scale = unsafe.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+ throw new Error("data type scale not a power of two");
+ shift = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
@@ -41,7 +39,7 @@
}
private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
+ return ((long) i << shift) + base;
}
/**
@@ -86,7 +84,7 @@
}
private int getRaw(long offset) {
- return U.getIntVolatile(array, offset);
+ return unsafe.getIntVolatile(array, offset);
}
/**
@@ -96,7 +94,7 @@
* @param newValue the new value
*/
public final void set(int i, int newValue) {
- U.putIntVolatile(array, checkedByteOffset(i), newValue);
+ unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
}
/**
@@ -107,7 +105,7 @@
* @since 1.6
*/
public final void lazySet(int i, int newValue) {
- U.putOrderedInt(array, checkedByteOffset(i), newValue);
+ unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
}
/**
@@ -119,7 +117,12 @@
* @return the previous value
*/
public final int getAndSet(int i, int newValue) {
- return U.getAndSetInt(array, checkedByteOffset(i), newValue);
+ long offset = checkedByteOffset(i);
+ while (true) {
+ int current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
+ return current;
+ }
}
/**
@@ -129,7 +132,7 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, int expect, int update) {
@@ -137,7 +140,7 @@
}
private boolean compareAndSetRaw(long offset, int expect, int update) {
- return U.compareAndSwapInt(array, offset, expect, update);
+ return unsafe.compareAndSwapInt(array, offset, expect, update);
}
/**
@@ -151,7 +154,7 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(int i, int expect, int update) {
return compareAndSet(i, expect, update);
@@ -185,7 +188,12 @@
* @return the previous value
*/
public final int getAndAdd(int i, int delta) {
- return U.getAndAddInt(array, checkedByteOffset(i), delta);
+ long offset = checkedByteOffset(i);
+ while (true) {
+ int current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, current + delta))
+ return current;
+ }
}
/**
@@ -195,7 +203,7 @@
* @return the updated value
*/
public final int incrementAndGet(int i) {
- return getAndAdd(i, 1) + 1;
+ return addAndGet(i, 1);
}
/**
@@ -205,7 +213,7 @@
* @return the updated value
*/
public final int decrementAndGet(int i) {
- return getAndAdd(i, -1) - 1;
+ return addAndGet(i, -1);
}
/**
@@ -216,101 +224,13 @@
* @return the updated value
*/
public final int addAndGet(int i, int delta) {
- return getAndAdd(i, delta) + delta;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final int getAndAccumulate(int i, int x,
- IntBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final int accumulateAndGet(int i, int x,
- IntBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ while (true) {
+ int current = getRaw(offset);
+ int next = current + delta;
+ if (compareAndSetRaw(offset, current, next))
+ return next;
+ }
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index 9c55491..15e8840 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -7,15 +7,12 @@
package java.util.concurrent.atomic;
import dalvik.system.VMStack; // android-added
+import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
-import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
-import java.util.function.IntBinaryOperator;
-import java.util.function.IntUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import java.security.PrivilegedActionException;
/**
* A reflection-based utility that enables atomic updates to
@@ -52,11 +49,8 @@
* or the field is inaccessible to the caller according to Java language
* access control
*/
- @CallerSensitive
- public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
- String fieldName) {
- return new AtomicIntegerFieldUpdaterImpl<U>
- (tclass, fieldName, VMStack.getStackClass1()); // android-changed
+ public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
+ return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
}
/**
@@ -75,7 +69,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
* @throws ClassCastException if {@code obj} is not an instance
* of the class possessing the field established in the constructor
*/
@@ -95,7 +89,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
* @throws ClassCastException if {@code obj} is not an instance
* of the class possessing the field established in the constructor
*/
@@ -139,11 +133,11 @@
* @return the previous value
*/
public int getAndSet(T obj, int newValue) {
- int prev;
- do {
- prev = get(obj);
- } while (!compareAndSet(obj, prev, newValue));
- return prev;
+ for (;;) {
+ int current = get(obj);
+ if (compareAndSet(obj, current, newValue))
+ return current;
+ }
}
/**
@@ -154,12 +148,12 @@
* @return the previous value
*/
public int getAndIncrement(T obj) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev + 1;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ int current = get(obj);
+ int next = current + 1;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -170,12 +164,12 @@
* @return the previous value
*/
public int getAndDecrement(T obj) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev - 1;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ int current = get(obj);
+ int next = current - 1;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -187,12 +181,12 @@
* @return the previous value
*/
public int getAndAdd(T obj, int delta) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev + delta;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ int current = get(obj);
+ int next = current + delta;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -203,12 +197,12 @@
* @return the updated value
*/
public int incrementAndGet(T obj) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev + 1;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ int current = get(obj);
+ int next = current + 1;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
/**
@@ -219,12 +213,12 @@
* @return the updated value
*/
public int decrementAndGet(T obj) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev - 1;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ int current = get(obj);
+ int next = current - 1;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
/**
@@ -236,131 +230,31 @@
* @return the updated value
*/
public int addAndGet(T obj, int delta) {
- int prev, next;
- do {
- prev = get(obj);
- next = prev + delta;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ int current = get(obj);
+ int next = current + delta;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
/**
- * 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
- * @return the previous value
- * @since 1.8
+ * Standard hotspot implementation using intrinsics
*/
- public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get(obj);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @return the updated value
- * @since 1.8
- */
- public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get(obj);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(obj, prev, next));
- return next;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final int getAndAccumulate(T obj, int x,
- IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final int accumulateAndGet(T obj, int x,
- IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return next;
- }
-
- /**
- * Standard hotspot implementation using intrinsics.
- */
- private static final class AtomicIntegerFieldUpdaterImpl<T>
- extends AtomicIntegerFieldUpdater<T> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long offset;
- /**
- * if field is protected, the subclass constructing updater, else
- * the same as tclass
- */
- private final Class<?> cclass;
- /** class holding the field */
private final Class<T> tclass;
+ private final Class<?> cclass;
- AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
- final String fieldName,
- final Class<?> caller) {
+ AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) {
final Field field;
+ final Class<?> caller;
final int modifiers;
try {
- field = AccessController.doPrivileged(
- new PrivilegedExceptionAction<Field>() {
- public Field run() throws NoSuchFieldException {
- return tclass.getDeclaredField(fieldName);
- }
- });
+ field = tclass.getDeclaredField(fieldName); // android-changed
+ caller = VMStack.getStackClass2(); // android-changed
+
modifiers = field.getModifiers();
// BEGIN android-removed
// sun.reflect.misc.ReflectUtil.ensureMemberAccess(
@@ -369,7 +263,7 @@
// ClassLoader ccl = caller.getClassLoader();
// if ((ccl != null) && (ccl != cl) &&
// ((cl == null) || !isAncestor(cl, ccl))) {
- // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
// }
// END android-removed
// BEGIN android-removed
@@ -380,15 +274,17 @@
throw new RuntimeException(ex);
}
- if (field.getType() != int.class)
+ Class<?> fieldt = field.getType();
+ if (fieldt != int.class)
throw new IllegalArgumentException("Must be integer type");
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ caller != tclass) ? caller : null;
this.tclass = tclass;
- this.offset = U.objectFieldOffset(field);
+ offset = unsafe.objectFieldOffset(field);
}
// BEGIN android-removed
@@ -397,7 +293,7 @@
// * classloader's delegation chain.
// * Equivalent to the inaccessible: first.isAncestor(second).
// */
- // private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+ // private static boolean isAncestor(ClassLoader first, ClassLoader second) {
// ClassLoader acl = first;
// do {
// acl = acl.getParent();
@@ -408,88 +304,51 @@
// return false;
// }
// END android-removed
-
- /**
- * Checks that target argument is instance of cclass. On
- * failure, throws cause.
- */
- private final void accessCheck(T obj) {
- if (!cclass.isInstance(obj))
- throwAccessCheckException(obj);
- }
-
- /**
- * Throws access exception if accessCheck failed due to
- * protected access, else ClassCastException.
- */
- private final void throwAccessCheckException(T obj) {
- if (cclass == tclass)
+ private void fullCheck(T obj) {
+ if (!tclass.isInstance(obj))
throw new ClassCastException();
- else
- throw new RuntimeException(
- new IllegalAccessException(
- "Class " +
- cclass.getName() +
- " can not access a protected member of class " +
- tclass.getName() +
- " using an instance of " +
- obj.getClass().getName()));
+ if (cclass != null)
+ ensureProtectedAccess(obj);
}
- public final boolean compareAndSet(T obj, int expect, int update) {
- accessCheck(obj);
- return U.compareAndSwapInt(obj, offset, expect, update);
+ public boolean compareAndSet(T obj, int expect, int update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.compareAndSwapInt(obj, offset, expect, update);
}
- public final boolean weakCompareAndSet(T obj, int expect, int update) {
- accessCheck(obj);
- return U.compareAndSwapInt(obj, offset, expect, update);
+ public boolean weakCompareAndSet(T obj, int expect, int update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.compareAndSwapInt(obj, offset, expect, update);
}
- public final void set(T obj, int newValue) {
- accessCheck(obj);
- U.putIntVolatile(obj, offset, newValue);
+ public void set(T obj, int newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putIntVolatile(obj, offset, newValue);
}
- public final void lazySet(T obj, int newValue) {
- accessCheck(obj);
- U.putOrderedInt(obj, offset, newValue);
+ public void lazySet(T obj, int newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putOrderedInt(obj, offset, newValue);
}
public final int get(T obj) {
- accessCheck(obj);
- return U.getIntVolatile(obj, offset);
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.getIntVolatile(obj, offset);
}
- public final int getAndSet(T obj, int newValue) {
- accessCheck(obj);
- return U.getAndSetInt(obj, offset, newValue);
+ private void ensureProtectedAccess(T obj) {
+ if (cclass.isInstance(obj)) {
+ return;
+ }
+ throw new RuntimeException(
+ new IllegalAccessException("Class " +
+ cclass.getName() +
+ " can not access a protected member of class " +
+ tclass.getName() +
+ " using an instance of " +
+ obj.getClass().getName()
+ )
+ );
}
-
- public final int getAndAdd(T obj, int delta) {
- accessCheck(obj);
- return U.getAndAddInt(obj, offset, delta);
- }
-
- public final int getAndIncrement(T obj) {
- return getAndAdd(obj, 1);
- }
-
- public final int getAndDecrement(T obj) {
- return getAndAdd(obj, -1);
- }
-
- public final int incrementAndGet(T obj) {
- return getAndAdd(obj, 1) + 1;
- }
-
- public final int decrementAndGet(T obj) {
- return getAndAdd(obj, -1) - 1;
- }
-
- public final int addAndGet(T obj, int delta) {
- return getAndAdd(obj, delta) + delta;
- }
-
}
}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
index fdb5f55..ab2961a 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
@@ -6,8 +6,7 @@
package java.util.concurrent.atomic;
-import java.util.function.LongBinaryOperator;
-import java.util.function.LongUnaryOperator;
+import sun.misc.Unsafe;
/**
* A {@code long} value that may be updated atomically. See the
@@ -25,8 +24,9 @@
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ // setup to use Unsafe.compareAndSwapLong for updates
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long valueOffset;
/**
* Records whether the underlying JVM supports lockless
@@ -44,11 +44,9 @@
static {
try {
- VALUE = U.objectFieldOffset
+ valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ } catch (Exception ex) { throw new Error(ex); }
}
private volatile long value;
@@ -83,9 +81,7 @@
* @param newValue the new value
*/
public final void set(long newValue) {
- // Use putLongVolatile instead of ordinary volatile store when
- // using compareAndSwapLong, for sake of some 32bit systems.
- U.putLongVolatile(this, VALUE, newValue);
+ value = newValue;
}
/**
@@ -95,7 +91,7 @@
* @since 1.6
*/
public final void lazySet(long newValue) {
- U.putOrderedLong(this, VALUE, newValue);
+ unsafe.putOrderedLong(this, valueOffset, newValue);
}
/**
@@ -105,7 +101,11 @@
* @return the previous value
*/
public final long getAndSet(long newValue) {
- return U.getAndSetLong(this, VALUE, newValue);
+ while (true) {
+ long current = get();
+ if (compareAndSet(current, newValue))
+ return current;
+ }
}
/**
@@ -114,11 +114,11 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(long expect, long update) {
- return U.compareAndSwapLong(this, VALUE, expect, update);
+ return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
/**
@@ -131,10 +131,10 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(long expect, long update) {
- return U.compareAndSwapLong(this, VALUE, expect, update);
+ return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
/**
@@ -143,7 +143,12 @@
* @return the previous value
*/
public final long getAndIncrement() {
- return U.getAndAddLong(this, VALUE, 1L);
+ while (true) {
+ long current = get();
+ long next = current + 1;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -152,7 +157,12 @@
* @return the previous value
*/
public final long getAndDecrement() {
- return U.getAndAddLong(this, VALUE, -1L);
+ while (true) {
+ long current = get();
+ long next = current - 1;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -162,7 +172,12 @@
* @return the previous value
*/
public final long getAndAdd(long delta) {
- return U.getAndAddLong(this, VALUE, delta);
+ while (true) {
+ long current = get();
+ long next = current + delta;
+ if (compareAndSet(current, next))
+ return current;
+ }
}
/**
@@ -171,7 +186,12 @@
* @return the updated value
*/
public final long incrementAndGet() {
- return U.getAndAddLong(this, VALUE, 1L) + 1L;
+ for (;;) {
+ long current = get();
+ long next = current + 1;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -180,7 +200,12 @@
* @return the updated value
*/
public final long decrementAndGet() {
- return U.getAndAddLong(this, VALUE, -1L) - 1L;
+ for (;;) {
+ long current = get();
+ long next = current - 1;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -190,93 +215,12 @@
* @return the updated value
*/
public final long addAndGet(long delta) {
- return U.getAndAddLong(this, VALUE, delta) + delta;
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final long getAndUpdate(LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final long updateAndGet(LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(prev, next));
- return next;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final long getAndAccumulate(long x,
- LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final long accumulateAndGet(long x,
- LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ for (;;) {
+ long current = get();
+ long next = current + delta;
+ if (compareAndSet(current, next))
+ return next;
+ }
}
/**
@@ -290,7 +234,6 @@
/**
* Returns the value of this {@code AtomicLong} as an {@code int}
* after a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
*/
public int intValue() {
return (int)get();
@@ -298,7 +241,6 @@
/**
* Returns the value of this {@code AtomicLong} as a {@code long}.
- * Equivalent to {@link #get()}.
*/
public long longValue() {
return get();
@@ -307,7 +249,6 @@
/**
* Returns the value of this {@code AtomicLong} as a {@code float}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
return (float)get();
@@ -316,7 +257,6 @@
/**
* Returns the value of this {@code AtomicLong} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
index 8da1501..b7f3d1e 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
@@ -6,8 +6,7 @@
package java.util.concurrent.atomic;
-import java.util.function.LongBinaryOperator;
-import java.util.function.LongUnaryOperator;
+import sun.misc.Unsafe;
/**
* A {@code long} array in which elements may be updated atomically.
@@ -19,17 +18,16 @@
public class AtomicLongArray implements java.io.Serializable {
private static final long serialVersionUID = -2308431214976778248L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final int base = unsafe.arrayBaseOffset(long[].class);
+ private static final int shift;
private final long[] array;
static {
- ABASE = U.arrayBaseOffset(long[].class);
- int scale = U.arrayIndexScale(long[].class);
+ int scale = unsafe.arrayIndexScale(long[].class);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+ throw new Error("data type scale not a power of two");
+ shift = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
@@ -40,7 +38,7 @@
}
private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
+ return ((long) i << shift) + base;
}
/**
@@ -85,7 +83,7 @@
}
private long getRaw(long offset) {
- return U.getLongVolatile(array, offset);
+ return unsafe.getLongVolatile(array, offset);
}
/**
@@ -95,7 +93,7 @@
* @param newValue the new value
*/
public final void set(int i, long newValue) {
- U.putLongVolatile(array, checkedByteOffset(i), newValue);
+ unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
}
/**
@@ -106,7 +104,7 @@
* @since 1.6
*/
public final void lazySet(int i, long newValue) {
- U.putOrderedLong(array, checkedByteOffset(i), newValue);
+ unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
}
/**
@@ -118,7 +116,12 @@
* @return the previous value
*/
public final long getAndSet(int i, long newValue) {
- return U.getAndSetLong(array, checkedByteOffset(i), newValue);
+ long offset = checkedByteOffset(i);
+ while (true) {
+ long current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
+ return current;
+ }
}
/**
@@ -128,7 +131,7 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, long expect, long update) {
@@ -136,7 +139,7 @@
}
private boolean compareAndSetRaw(long offset, long expect, long update) {
- return U.compareAndSwapLong(array, offset, expect, update);
+ return unsafe.compareAndSwapLong(array, offset, expect, update);
}
/**
@@ -150,7 +153,7 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(int i, long expect, long update) {
return compareAndSet(i, expect, update);
@@ -184,7 +187,12 @@
* @return the previous value
*/
public final long getAndAdd(int i, long delta) {
- return U.getAndAddLong(array, checkedByteOffset(i), delta);
+ long offset = checkedByteOffset(i);
+ while (true) {
+ long current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, current + delta))
+ return current;
+ }
}
/**
@@ -194,7 +202,7 @@
* @return the updated value
*/
public final long incrementAndGet(int i) {
- return getAndAdd(i, 1) + 1;
+ return addAndGet(i, 1);
}
/**
@@ -204,7 +212,7 @@
* @return the updated value
*/
public final long decrementAndGet(int i) {
- return getAndAdd(i, -1) - 1;
+ return addAndGet(i, -1);
}
/**
@@ -215,101 +223,13 @@
* @return the updated value
*/
public long addAndGet(int i, long delta) {
- return getAndAdd(i, delta) + delta;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final long getAndAccumulate(int i, long x,
- LongBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final long accumulateAndGet(int i, long x,
- LongBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ while (true) {
+ long current = getRaw(offset);
+ long next = current + delta;
+ if (compareAndSetRaw(offset, current, next))
+ return next;
+ }
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index c1a02b5..65bd452 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -7,15 +7,9 @@
package java.util.concurrent.atomic;
import dalvik.system.VMStack; // android-added
+import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.function.LongBinaryOperator;
-import java.util.function.LongUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
/**
* A reflection-based utility that enables atomic updates to
@@ -52,14 +46,11 @@
* or the field is inaccessible to the caller according to Java language
* access control
*/
- @CallerSensitive
- public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
- String fieldName) {
- Class<?> caller = VMStack.getStackClass1(); // android-changed
+ public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
- return new CASUpdater<U>(tclass, fieldName, caller);
+ return new CASUpdater<U>(tclass, fieldName);
else
- return new LockedUpdater<U>(tclass, fieldName, caller);
+ return new LockedUpdater<U>(tclass, fieldName);
}
/**
@@ -78,7 +69,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
* @throws ClassCastException if {@code obj} is not an instance
* of the class possessing the field established in the constructor
*/
@@ -98,7 +89,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
* @throws ClassCastException if {@code obj} is not an instance
* of the class possessing the field established in the constructor
*/
@@ -142,11 +133,11 @@
* @return the previous value
*/
public long getAndSet(T obj, long newValue) {
- long prev;
- do {
- prev = get(obj);
- } while (!compareAndSet(obj, prev, newValue));
- return prev;
+ for (;;) {
+ long current = get(obj);
+ if (compareAndSet(obj, current, newValue))
+ return current;
+ }
}
/**
@@ -157,12 +148,12 @@
* @return the previous value
*/
public long getAndIncrement(T obj) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev + 1;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ long current = get(obj);
+ long next = current + 1;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -173,12 +164,12 @@
* @return the previous value
*/
public long getAndDecrement(T obj) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev - 1;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ long current = get(obj);
+ long next = current - 1;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -190,12 +181,12 @@
* @return the previous value
*/
public long getAndAdd(T obj, long delta) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev + delta;
- } while (!compareAndSet(obj, prev, next));
- return prev;
+ for (;;) {
+ long current = get(obj);
+ long next = current + delta;
+ if (compareAndSet(obj, current, next))
+ return current;
+ }
}
/**
@@ -206,12 +197,12 @@
* @return the updated value
*/
public long incrementAndGet(T obj) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev + 1;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ long current = get(obj);
+ long next = current + 1;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
/**
@@ -222,12 +213,12 @@
* @return the updated value
*/
public long decrementAndGet(T obj) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev - 1;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ long current = get(obj);
+ long next = current - 1;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
/**
@@ -239,121 +230,27 @@
* @return the updated value
*/
public long addAndGet(T obj, long delta) {
- long prev, next;
- do {
- prev = get(obj);
- next = prev + delta;
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ long current = get(obj);
+ long next = current + delta;
+ if (compareAndSet(obj, current, next))
+ return next;
+ }
}
- /**
- * 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
- * @return the previous value
- * @since 1.8
- */
- public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get(obj);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @return the updated value
- * @since 1.8
- */
- public final long updateAndGet(T obj, LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get(obj);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(obj, prev, next));
- return next;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final long getAndAccumulate(T obj, long x,
- LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final long accumulateAndGet(T obj, long x,
- LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return next;
- }
-
- private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long offset;
- /**
- * if field is protected, the subclass constructing updater, else
- * the same as tclass
- */
- private final Class<?> cclass;
- /** class holding the field */
private final Class<T> tclass;
+ private final Class<?> cclass;
- CASUpdater(final Class<T> tclass, final String fieldName,
- final Class<?> caller) {
+ CASUpdater(final Class<T> tclass, final String fieldName) {
final Field field;
+ final Class<?> caller;
final int modifiers;
try {
field = tclass.getDeclaredField(fieldName); // android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
// BEGIN android-removed
// sun.reflect.misc.ReflectUtil.ensureMemberAccess(
@@ -362,128 +259,92 @@
// ClassLoader ccl = caller.getClassLoader();
// if ((ccl != null) && (ccl != cl) &&
// ((cl == null) || !isAncestor(cl, ccl))) {
- // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
// }
// END android-removed
// BEGIN android-removed
// } catch (PrivilegedActionException pae) {
- // throw new RuntimeException(pae.getException());
+ // throw new RuntimeException(pae.getException());
// END android-removed
} catch (Exception ex) {
throw new RuntimeException(ex);
}
- if (field.getType() != long.class)
+ Class<?> fieldt = field.getType();
+ if (fieldt != long.class)
throw new IllegalArgumentException("Must be long type");
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ caller != tclass) ? caller : null;
this.tclass = tclass;
- this.offset = U.objectFieldOffset(field);
+ offset = unsafe.objectFieldOffset(field);
}
- /**
- * Checks that target argument is instance of cclass. On
- * failure, throws cause.
- */
- private final void accessCheck(T obj) {
- if (!cclass.isInstance(obj))
- throwAccessCheckException(obj);
- }
-
- /**
- * Throws access exception if accessCheck failed due to
- * protected access, else ClassCastException.
- */
- private final void throwAccessCheckException(T obj) {
- if (cclass == tclass)
+ private void fullCheck(T obj) {
+ if (!tclass.isInstance(obj))
throw new ClassCastException();
- else
- throw new RuntimeException(
- new IllegalAccessException(
- "Class " +
- cclass.getName() +
- " can not access a protected member of class " +
- tclass.getName() +
- " using an instance of " +
- obj.getClass().getName()));
+ if (cclass != null)
+ ensureProtectedAccess(obj);
}
- public final boolean compareAndSet(T obj, long expect, long update) {
- accessCheck(obj);
- return U.compareAndSwapLong(obj, offset, expect, update);
+ public boolean compareAndSet(T obj, long expect, long update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.compareAndSwapLong(obj, offset, expect, update);
}
- public final boolean weakCompareAndSet(T obj, long expect, long update) {
- accessCheck(obj);
- return U.compareAndSwapLong(obj, offset, expect, update);
+ public boolean weakCompareAndSet(T obj, long expect, long update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.compareAndSwapLong(obj, offset, expect, update);
}
- public final void set(T obj, long newValue) {
- accessCheck(obj);
- U.putLongVolatile(obj, offset, newValue);
+ public void set(T obj, long newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putLongVolatile(obj, offset, newValue);
}
- public final void lazySet(T obj, long newValue) {
- accessCheck(obj);
- U.putOrderedLong(obj, offset, newValue);
+ public void lazySet(T obj, long newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ unsafe.putOrderedLong(obj, offset, newValue);
}
- public final long get(T obj) {
- accessCheck(obj);
- return U.getLongVolatile(obj, offset);
+ public long get(T obj) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
+ return unsafe.getLongVolatile(obj, offset);
}
- public final long getAndSet(T obj, long newValue) {
- accessCheck(obj);
- return U.getAndSetLong(obj, offset, newValue);
- }
-
- public final long getAndAdd(T obj, long delta) {
- accessCheck(obj);
- return U.getAndAddLong(obj, offset, delta);
- }
-
- public final long getAndIncrement(T obj) {
- return getAndAdd(obj, 1);
- }
-
- public final long getAndDecrement(T obj) {
- return getAndAdd(obj, -1);
- }
-
- public final long incrementAndGet(T obj) {
- return getAndAdd(obj, 1) + 1;
- }
-
- public final long decrementAndGet(T obj) {
- return getAndAdd(obj, -1) - 1;
- }
-
- public final long addAndGet(T obj, long delta) {
- return getAndAdd(obj, delta) + delta;
+ private void ensureProtectedAccess(T obj) {
+ if (cclass.isInstance(obj)) {
+ return;
+ }
+ throw new RuntimeException(
+ new IllegalAccessException("Class " +
+ cclass.getName() +
+ " can not access a protected member of class " +
+ tclass.getName() +
+ " using an instance of " +
+ obj.getClass().getName()
+ )
+ );
}
}
- private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private final long offset;
- /**
- * if field is protected, the subclass constructing updater, else
- * the same as tclass
- */
- private final Class<?> cclass;
- /** class holding the field */
- private final Class<T> tclass;
- LockedUpdater(final Class<T> tclass, final String fieldName,
- final Class<?> caller) {
+ private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private final long offset;
+ private final Class<T> tclass;
+ private final Class<?> cclass;
+
+ LockedUpdater(final Class<T> tclass, final String fieldName) {
Field field = null;
+ Class<?> caller = null;
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName); // android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
// BEGIN android-removed
// sun.reflect.misc.ReflectUtil.ensureMemberAccess(
@@ -492,7 +353,7 @@
// ClassLoader ccl = caller.getClassLoader();
// if ((ccl != null) && (ccl != cl) &&
// ((cl == null) || !isAncestor(cl, ccl))) {
- // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
// }
// END android-removed
// BEGIN android-removed
@@ -503,76 +364,73 @@
throw new RuntimeException(ex);
}
- if (field.getType() != long.class)
+ Class<?> fieldt = field.getType();
+ if (fieldt != long.class)
throw new IllegalArgumentException("Must be long type");
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ caller != tclass) ? caller : null;
this.tclass = tclass;
- this.offset = U.objectFieldOffset(field);
+ offset = unsafe.objectFieldOffset(field);
}
- /**
- * Checks that target argument is instance of cclass. On
- * failure, throws cause.
- */
- private final void accessCheck(T obj) {
- if (!cclass.isInstance(obj))
- throw accessCheckException(obj);
+ private void fullCheck(T obj) {
+ if (!tclass.isInstance(obj))
+ throw new ClassCastException();
+ if (cclass != null)
+ ensureProtectedAccess(obj);
}
- /**
- * Returns access exception if accessCheck failed due to
- * protected access, else ClassCastException.
- */
- private final RuntimeException accessCheckException(T obj) {
- if (cclass == tclass)
- return new ClassCastException();
- else
- return new RuntimeException(
- new IllegalAccessException(
- "Class " +
- cclass.getName() +
- " can not access a protected member of class " +
- tclass.getName() +
- " using an instance of " +
- obj.getClass().getName()));
- }
-
- public final boolean compareAndSet(T obj, long expect, long update) {
- accessCheck(obj);
+ public boolean compareAndSet(T obj, long expect, long update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
synchronized (this) {
- long v = U.getLong(obj, offset);
+ long v = unsafe.getLong(obj, offset);
if (v != expect)
return false;
- U.putLong(obj, offset, update);
+ unsafe.putLong(obj, offset, update);
return true;
}
}
- public final boolean weakCompareAndSet(T obj, long expect, long update) {
+ public boolean weakCompareAndSet(T obj, long expect, long update) {
return compareAndSet(obj, expect, update);
}
- public final void set(T obj, long newValue) {
- accessCheck(obj);
+ public void set(T obj, long newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
synchronized (this) {
- U.putLong(obj, offset, newValue);
+ unsafe.putLong(obj, offset, newValue);
}
}
- public final void lazySet(T obj, long newValue) {
+ public void lazySet(T obj, long newValue) {
set(obj, newValue);
}
- public final long get(T obj) {
- accessCheck(obj);
+ public long get(T obj) {
+ if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
synchronized (this) {
- return U.getLong(obj, offset);
+ return unsafe.getLong(obj, offset);
}
}
+
+ private void ensureProtectedAccess(T obj) {
+ if (cclass.isInstance(obj)) {
+ return;
+ }
+ throw new RuntimeException(
+ new IllegalAccessException("Class " +
+ cclass.getName() +
+ " can not access a protected member of class " +
+ tclass.getName() +
+ " using an instance of " +
+ obj.getClass().getName()
+ )
+ );
+ }
}
// BEGIN android-removed
@@ -581,13 +439,13 @@
// * classloader's delegation chain.
// * Equivalent to the inaccessible: first.isAncestor(second).
// */
- // static boolean isAncestor(ClassLoader first, ClassLoader second) {
+ // private static boolean isAncestor(ClassLoader first, ClassLoader second) {
// ClassLoader acl = first;
// do {
// acl = acl.getParent();
// if (second == acl) {
// return true;
- // }
+ // }
// } while (acl != null);
// return false;
// }
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index d11be10..18d148f 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -91,7 +91,7 @@
* @param newReference the new value for the reference
* @param expectedMark the expected value of the mark
* @param newMark the new value for the mark
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean weakCompareAndSet(V expectedReference,
V newReference,
@@ -111,7 +111,7 @@
* @param newReference the new value for the reference
* @param expectedMark the expected value of the mark
* @param newMark the new value for the mark
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
@@ -149,7 +149,7 @@
*
* @param expectedReference the expected value of the reference
* @param newMark the new value for the mark
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean attemptMark(V expectedReference, boolean newMark) {
Pair<V> current = pair;
@@ -161,18 +161,23 @@
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PAIR;
- static {
- try {
- PAIR = U.objectFieldOffset
- (AtomicMarkableReference.class.getDeclaredField("pair"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+ private static final long pairOffset =
+ objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
+ }
+
+ static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
+ String field, Class<?> klazz) {
+ try {
+ return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
+ } catch (NoSuchFieldException e) {
+ // Convert Exception to corresponding Error
+ NoSuchFieldError error = new NoSuchFieldError(field);
+ error.initCause(e);
+ throw error;
+ }
}
}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
index c3a5ede..7ea6066 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
@@ -6,8 +6,7 @@
package java.util.concurrent.atomic;
-import java.util.function.BinaryOperator;
-import java.util.function.UnaryOperator;
+import sun.misc.Unsafe;
/**
* An object reference that may be updated atomically. See the {@link
@@ -20,16 +19,14 @@
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long valueOffset;
static {
try {
- VALUE = U.objectFieldOffset
+ valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ } catch (Exception ex) { throw new Error(ex); }
}
private volatile V value;
@@ -74,7 +71,7 @@
* @since 1.6
*/
public final void lazySet(V newValue) {
- U.putOrderedObject(this, VALUE, newValue);
+ unsafe.putOrderedObject(this, valueOffset, newValue);
}
/**
@@ -82,11 +79,11 @@
* if the current value {@code ==} the expected value.
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(V expect, V update) {
- return U.compareAndSwapObject(this, VALUE, expect, update);
+ return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
/**
@@ -99,10 +96,10 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(V expect, V update) {
- return U.compareAndSwapObject(this, VALUE, expect, update);
+ return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
/**
@@ -111,95 +108,12 @@
* @param newValue the new value
* @return the previous value
*/
- @SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
- return (V)U.getAndSetObject(this, VALUE, newValue);
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final V getAndUpdate(UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get();
- next = updateFunction.apply(prev);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final V updateAndGet(UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get();
- next = updateFunction.apply(prev);
- } while (!compareAndSet(prev, next));
- return next;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final V getAndAccumulate(V x,
- BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get();
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the current value 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 x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final V accumulateAndGet(V x,
- BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get();
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ while (true) {
+ V x = get();
+ if (compareAndSet(x, newValue))
+ return x;
+ }
}
/**
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
index f5596e8..052b839 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -6,10 +6,9 @@
package java.util.concurrent.atomic;
-import java.lang.reflect.Array;
import java.util.Arrays;
-import java.util.function.BinaryOperator;
-import java.util.function.UnaryOperator;
+import java.lang.reflect.Array;
+import sun.misc.Unsafe;
/**
* An array of object references in which elements may be updated
@@ -23,22 +22,23 @@
public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final long serialVersionUID = -6209656149925076980L;
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long ARRAY;
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final Unsafe unsafe;
+ private static final int base;
+ private static final int shift;
+ private static final long arrayFieldOffset;
private final Object[] array; // must have exact type Object[]
static {
try {
- ARRAY = U.objectFieldOffset
+ unsafe = Unsafe.getUnsafe();
+ arrayFieldOffset = unsafe.objectFieldOffset
(AtomicReferenceArray.class.getDeclaredField("array"));
- ABASE = U.arrayBaseOffset(Object[].class);
- int scale = U.arrayIndexScale(Object[].class);
+ base = unsafe.arrayBaseOffset(Object[].class);
+ int scale = unsafe.arrayIndexScale(Object[].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("data type scale not a power of two");
+ shift = 31 - Integer.numberOfLeadingZeros(scale);
+ } catch (Exception e) {
throw new Error(e);
}
}
@@ -51,7 +51,7 @@
}
private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
+ return ((long) i << shift) + base;
}
/**
@@ -97,7 +97,7 @@
@SuppressWarnings("unchecked")
private E getRaw(long offset) {
- return (E) U.getObjectVolatile(array, offset);
+ return (E) unsafe.getObjectVolatile(array, offset);
}
/**
@@ -107,7 +107,7 @@
* @param newValue the new value
*/
public final void set(int i, E newValue) {
- U.putObjectVolatile(array, checkedByteOffset(i), newValue);
+ unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
}
/**
@@ -118,7 +118,7 @@
* @since 1.6
*/
public final void lazySet(int i, E newValue) {
- U.putOrderedObject(array, checkedByteOffset(i), newValue);
+ unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
}
/**
@@ -129,9 +129,13 @@
* @param newValue the new value
* @return the previous value
*/
- @SuppressWarnings("unchecked")
public final E getAndSet(int i, E newValue) {
- return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
+ long offset = checkedByteOffset(i);
+ while (true) {
+ E current = getRaw(offset);
+ if (compareAndSetRaw(offset, current, newValue))
+ return current;
+ }
}
/**
@@ -141,7 +145,7 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that
+ * @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, E expect, E update) {
@@ -149,7 +153,7 @@
}
private boolean compareAndSetRaw(long offset, E expect, E update) {
- return U.compareAndSwapObject(array, offset, expect, update);
+ return unsafe.compareAndSwapObject(array, offset, expect, update);
}
/**
@@ -163,107 +167,13 @@
* @param i the index
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public final boolean weakCompareAndSet(int i, E expect, E update) {
return compareAndSet(i, expect, update);
}
/**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.apply(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 i the index
- * @param updateFunction a side-effect-free function
- * @return the updated value
- * @since 1.8
- */
- public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.apply(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final E getAndAccumulate(int i, E x,
- BinaryOperator<E> accumulatorFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
- }
-
- /**
- * Atomically updates the element at index {@code i} 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 at index {@code i} as its first
- * argument, and the given update as the second argument.
- *
- * @param i the index
- * @param x the update value
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final E accumulateAndGet(int i, E x,
- BinaryOperator<E> accumulatorFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
- }
-
- /**
* Returns the String representation of the current values of array.
* @return the String representation of the current values of array
*/
@@ -284,20 +194,17 @@
/**
* 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
- * @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
+ throws java.io.IOException, ClassNotFoundException,
+ java.io.InvalidObjectException {
// Note: This must be changed if any additional fields are defined
Object a = s.readFields().get("array", null);
if (a == null || !a.getClass().isArray())
throw new java.io.InvalidObjectException("Not array type");
if (a.getClass() != Object[].class)
a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
- U.putObjectVolatile(this, ARRAY, a);
+ unsafe.putObjectVolatile(this, arrayFieldOffset, a);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 1dc2eb9..13ad3eb 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -7,15 +7,9 @@
package java.util.concurrent.atomic;
import dalvik.system.VMStack; // android-added
+import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.function.BinaryOperator;
-import java.util.function.UnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
/**
* A reflection-based utility that enables atomic updates to
@@ -25,7 +19,7 @@
* independently subject to atomic updates. For example, a tree node
* might be declared as
*
- * <pre> {@code
+ * <pre> {@code
* class Node {
* private volatile Node left, right;
*
@@ -66,19 +60,17 @@
* @param <U> the type of instances of tclass
* @param <W> the type of instances of vclass
* @return the updater
- * @throws ClassCastException if the field is of the wrong type
- * @throws IllegalArgumentException if the field is not volatile
+ * @throws IllegalArgumentException if the field is not a volatile reference type
* @throws RuntimeException with a nested reflection-based
* exception if the class does not hold field or is the wrong type,
* or the field is inaccessible to the caller according to Java language
* access control
*/
- @CallerSensitive
public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
Class<W> vclass,
String fieldName) {
return new AtomicReferenceFieldUpdaterImpl<U,W>
- (tclass, vclass, fieldName, VMStack.getStackClass1()); // android-changed
+ (tclass, vclass, fieldName);
}
/**
@@ -97,7 +89,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public abstract boolean compareAndSet(T obj, V expect, V update);
@@ -115,7 +107,7 @@
* @param obj An object whose field to conditionally set
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful
+ * @return true if successful
*/
public abstract boolean weakCompareAndSet(T obj, V expect, V update);
@@ -157,116 +149,20 @@
* @return the previous value
*/
public V getAndSet(T obj, V newValue) {
- V prev;
- do {
- prev = get(obj);
- } while (!compareAndSet(obj, prev, newValue));
- return prev;
- }
-
- /**
- * 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
- * @return the previous value
- * @since 1.8
- */
- public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get(obj);
- next = updateFunction.apply(prev);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @return the updated value
- * @since 1.8
- */
- public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get(obj);
- next = updateFunction.apply(prev);
- } while (!compareAndSet(obj, prev, next));
- return next;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the previous value
- * @since 1.8
- */
- public final V getAndAccumulate(T obj, V x,
- BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return prev;
- }
-
- /**
- * 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
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @return the updated value
- * @since 1.8
- */
- public final V accumulateAndGet(T obj, V x,
- BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get(obj);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(obj, prev, next));
- return next;
+ for (;;) {
+ V current = get(obj);
+ if (compareAndSet(obj, current, newValue))
+ return current;
+ }
}
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long offset;
- /**
- * if field is protected, the subclass constructing updater, else
- * the same as tclass
- */
- private final Class<?> cclass;
- /** class holding the field */
private final Class<T> tclass;
- /** field value type */
private final Class<V> vclass;
+ private final Class<?> cclass;
/*
* Internal type checks within all update methods contain
@@ -281,25 +177,26 @@
*/
AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
- final Class<V> vclass,
- final String fieldName,
- final Class<?> caller) {
+ Class<V> vclass,
+ final String fieldName) {
final Field field;
final Class<?> fieldClass;
+ final Class<?> caller;
final int modifiers;
try {
field = tclass.getDeclaredField(fieldName); // android-changed
+ caller = VMStack.getStackClass2(); // android-changed
modifiers = field.getModifiers();
- // BEGIN android-removed
- // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
- // caller, tclass, null, modifiers);
- // ClassLoader cl = tclass.getClassLoader();
- // ClassLoader ccl = caller.getClassLoader();
- // if ((ccl != null) && (ccl != cl) &&
- // ((cl == null) || !isAncestor(cl, ccl))) {
- // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
- // }
- // END android-removed
+ // BEGIN android-removed
+ // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+ // caller, tclass, null, modifiers);
+ // ClassLoader cl = tclass.getClassLoader();
+ // ClassLoader ccl = caller.getClassLoader();
+ // if ((ccl != null) && (ccl != cl) &&
+ // ((cl == null) || !isAncestor(cl, ccl))) {
+ // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+ // }
+ // END android-removed
fieldClass = field.getType();
// BEGIN android-removed
// } catch (PrivilegedActionException pae) {
@@ -311,16 +208,18 @@
if (vclass != fieldClass)
throw new ClassCastException();
- if (vclass.isPrimitive())
- throw new IllegalArgumentException("Must be reference type");
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ caller != tclass) ? caller : null;
this.tclass = tclass;
- this.vclass = vclass;
- this.offset = U.objectFieldOffset(field);
+ if (vclass == Object.class)
+ this.vclass = null;
+ else
+ this.vclass = vclass;
+ offset = unsafe.objectFieldOffset(field);
}
// BEGIN android-removed
@@ -329,90 +228,87 @@
// * classloader's delegation chain.
// * Equivalent to the inaccessible: first.isAncestor(second).
// */
+ //
// private static boolean isAncestor(ClassLoader first, ClassLoader second) {
// ClassLoader acl = first;
// do {
// acl = acl.getParent();
// if (second == acl) {
// return true;
- // }
+ // }
// } while (acl != null);
// return false;
// }
// END android-removed
- /**
- * Checks that target argument is instance of cclass. On
- * failure, throws cause.
- */
- private final void accessCheck(T obj) {
- if (!cclass.isInstance(obj))
- throwAccessCheckException(obj);
- }
-
- /**
- * Throws access exception if accessCheck failed due to
- * protected access, else ClassCastException.
- */
- private final void throwAccessCheckException(T obj) {
- if (cclass == tclass)
+ void targetCheck(T obj) {
+ if (!tclass.isInstance(obj))
throw new ClassCastException();
- else
- throw new RuntimeException(
- new IllegalAccessException(
- "Class " +
- cclass.getName() +
- " can not access a protected member of class " +
- tclass.getName() +
- " using an instance of " +
- obj.getClass().getName()));
+ if (cclass != null)
+ ensureProtectedAccess(obj);
}
- private final void valueCheck(V v) {
- if (v != null && !(vclass.isInstance(v)))
- throwCCE();
+ void updateCheck(T obj, V update) {
+ if (!tclass.isInstance(obj) ||
+ (update != null && vclass != null && !vclass.isInstance(update)))
+ throw new ClassCastException();
+ if (cclass != null)
+ ensureProtectedAccess(obj);
}
- static void throwCCE() {
- throw new ClassCastException();
+ public boolean compareAndSet(T obj, V expect, V update) {
+ if (obj == null || obj.getClass() != tclass || cclass != null ||
+ (update != null && vclass != null &&
+ vclass != update.getClass()))
+ updateCheck(obj, update);
+ return unsafe.compareAndSwapObject(obj, offset, expect, update);
}
- public final boolean compareAndSet(T obj, V expect, V update) {
- accessCheck(obj);
- valueCheck(update);
- return U.compareAndSwapObject(obj, offset, expect, update);
- }
-
- public final boolean weakCompareAndSet(T obj, V expect, V update) {
+ public boolean weakCompareAndSet(T obj, V expect, V update) {
// same implementation as strong form for now
- accessCheck(obj);
- valueCheck(update);
- return U.compareAndSwapObject(obj, offset, expect, update);
+ if (obj == null || obj.getClass() != tclass || cclass != null ||
+ (update != null && vclass != null &&
+ vclass != update.getClass()))
+ updateCheck(obj, update);
+ return unsafe.compareAndSwapObject(obj, offset, expect, update);
}
- public final void set(T obj, V newValue) {
- accessCheck(obj);
- valueCheck(newValue);
- U.putObjectVolatile(obj, offset, newValue);
+ public void set(T obj, V newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null ||
+ (newValue != null && vclass != null &&
+ vclass != newValue.getClass()))
+ updateCheck(obj, newValue);
+ unsafe.putObjectVolatile(obj, offset, newValue);
}
- public final void lazySet(T obj, V newValue) {
- accessCheck(obj);
- valueCheck(newValue);
- U.putOrderedObject(obj, offset, newValue);
+ public void lazySet(T obj, V newValue) {
+ if (obj == null || obj.getClass() != tclass || cclass != null ||
+ (newValue != null && vclass != null &&
+ vclass != newValue.getClass()))
+ updateCheck(obj, newValue);
+ unsafe.putOrderedObject(obj, offset, newValue);
}
@SuppressWarnings("unchecked")
- public final V get(T obj) {
- accessCheck(obj);
- return (V)U.getObjectVolatile(obj, offset);
+ public V get(T obj) {
+ if (obj == null || obj.getClass() != tclass || cclass != null)
+ targetCheck(obj);
+ return (V)unsafe.getObjectVolatile(obj, offset);
}
- @SuppressWarnings("unchecked")
- public final V getAndSet(T obj, V newValue) {
- accessCheck(obj);
- valueCheck(newValue);
- return (V)U.getAndSetObject(obj, offset, newValue);
+ private void ensureProtectedAccess(T obj) {
+ if (cclass.isInstance(obj)) {
+ return;
+ }
+ throw new RuntimeException(
+ new IllegalAccessException("Class " +
+ cclass.getName() +
+ " can not access a protected member of class " +
+ tclass.getName() +
+ " using an instance of " +
+ obj.getClass().getName()
+ )
+ );
}
}
}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index 69fab23..1449856 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -91,7 +91,7 @@
* @param newReference the new value for the reference
* @param expectedStamp the expected value of the stamp
* @param newStamp the new value for the stamp
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean weakCompareAndSet(V expectedReference,
V newReference,
@@ -111,7 +111,7 @@
* @param newReference the new value for the reference
* @param expectedStamp the expected value of the stamp
* @param newStamp the new value for the stamp
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
@@ -149,7 +149,7 @@
*
* @param expectedReference the expected value of the reference
* @param newStamp the new value for the stamp
- * @return {@code true} if successful
+ * @return true if successful
*/
public boolean attemptStamp(V expectedReference, int newStamp) {
Pair<V> current = pair;
@@ -161,18 +161,23 @@
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PAIR;
- static {
- try {
- PAIR = U.objectFieldOffset
- (AtomicStampedReference.class.getDeclaredField("pair"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+ private static final long pairOffset =
+ objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
+ }
+
+ static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
+ String field, Class<?> klazz) {
+ try {
+ return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
+ } catch (NoSuchFieldException e) {
+ // Convert Exception to corresponding Error
+ NoSuchFieldError error = new NoSuchFieldError(field);
+ error.initCause(e);
+ throw error;
+ }
}
}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/DoubleAccumulator.java b/luni/src/main/java/java/util/concurrent/atomic/DoubleAccumulator.java
deleted file mode 100644
index 1ea088d..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/DoubleAccumulator.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * 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.atomic;
-
-import java.io.Serializable;
-import java.util.function.DoubleBinaryOperator;
-
-/**
- * One or more variables that together maintain a running {@code double}
- * value updated using a supplied function. When updates (method
- * {@link #accumulate}) are contended across threads, the set of variables
- * may grow dynamically to reduce contention. Method {@link #get}
- * (or, equivalently, {@link #doubleValue}) returns the current value
- * across the variables maintaining updates.
- *
- * <p>This class is usually preferable to alternatives when multiple
- * threads update a common value that is used for purposes such as
- * summary statistics that are frequently updated but less frequently
- * read.
- *
- * <p>The supplied accumulator 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. For example, to maintain a running maximum value, you
- * could supply {@code Double::max} along with {@code
- * Double.NEGATIVE_INFINITY} as the identity. The order of
- * accumulation within or across threads is not guaranteed. Thus, this
- * class may not be applicable if numerical stability is required,
- * especially when combining values of substantially different orders
- * of magnitude.
- *
- * <p>Class {@link DoubleAdder} provides analogs of the functionality
- * of this class for the common special case of maintaining sums. The
- * call {@code new DoubleAdder()} is equivalent to {@code new
- * DoubleAccumulator((x, y) -> x + y, 0.0)}.
- *
- * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code equals}, {@code hashCode} and {@code
- * compareTo} because instances are expected to be mutated, and so are
- * not useful as collection keys.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class DoubleAccumulator extends Striped64 implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- private final DoubleBinaryOperator function;
- private final long identity; // use long representation
-
- /**
- * Creates a new instance using the given accumulator function
- * and identity element.
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @param identity identity (initial value) for the accumulator function
- */
- public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction,
- double identity) {
- this.function = accumulatorFunction;
- base = this.identity = Double.doubleToRawLongBits(identity);
- }
-
- /**
- * Updates with the given value.
- *
- * @param x the value
- */
- public void accumulate(double x) {
- Cell[] as; long b, v, r; int m; Cell a;
- if ((as = cells) != null ||
- (r = Double.doubleToRawLongBits
- (function.applyAsDouble
- (Double.longBitsToDouble(b = base), x))) != b && !casBase(b, r)) {
- boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[getProbe() & m]) == null ||
- !(uncontended =
- (r = Double.doubleToRawLongBits
- (function.applyAsDouble
- (Double.longBitsToDouble(v = a.value), x))) == v ||
- a.cas(v, r)))
- doubleAccumulate(x, function, uncontended);
- }
- }
-
- /**
- * Returns the current value. The returned value is <em>NOT</em>
- * an atomic snapshot; invocation in the absence of concurrent
- * updates returns an accurate result, but concurrent updates that
- * occur while the value is being calculated might not be
- * incorporated.
- *
- * @return the current value
- */
- public double get() {
- Cell[] as = cells;
- double result = Double.longBitsToDouble(base);
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- result = function.applyAsDouble
- (result, Double.longBitsToDouble(a.value));
- }
- return result;
- }
-
- /**
- * Resets variables maintaining updates to the identity value.
- * This method may be a useful alternative to creating a new
- * updater, but is only effective if there are no concurrent
- * updates. Because this method is intrinsically racy, it should
- * only be used when it is known that no threads are concurrently
- * updating.
- */
- public void reset() {
- Cell[] as = cells;
- base = identity;
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- a.reset(identity);
- }
- }
-
- /**
- * Equivalent in effect to {@link #get} followed by {@link
- * #reset}. This method may apply for example during quiescent
- * points between multithreaded computations. If there are
- * updates concurrent with this method, the returned value is
- * <em>not</em> guaranteed to be the final value occurring before
- * the reset.
- *
- * @return the value before reset
- */
- public double getThenReset() {
- Cell[] as = cells;
- double result = Double.longBitsToDouble(base);
- base = identity;
- if (as != null) {
- for (Cell a : as) {
- if (a != null) {
- double v = Double.longBitsToDouble(a.value);
- a.reset(identity);
- result = function.applyAsDouble(result, v);
- }
- }
- }
- return result;
- }
-
- /**
- * Returns the String representation of the current value.
- * @return the String representation of the current value
- */
- public String toString() {
- return Double.toString(get());
- }
-
- /**
- * Equivalent to {@link #get}.
- *
- * @return the current value
- */
- public double doubleValue() {
- return get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as a {@code long}
- * after a narrowing primitive conversion.
- */
- public long longValue() {
- return (long)get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as an {@code int}
- * after a narrowing primitive conversion.
- */
- public int intValue() {
- return (int)get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as a {@code float}
- * after a narrowing primitive conversion.
- */
- public float floatValue() {
- return (float)get();
- }
-
- /**
- * Serialization proxy, used to avoid reference to the non-public
- * Striped64 superclass in serialized forms.
- * @serial include
- */
- private static class SerializationProxy implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * The current value returned by get().
- * @serial
- */
- private final double value;
-
- /**
- * The function used for updates.
- * @serial
- */
- private final DoubleBinaryOperator function;
-
- /**
- * The identity value, represented as a long, as converted by
- * {@link Double#doubleToRawLongBits}. The original identity
- * can be recovered using {@link Double#longBitsToDouble}.
- * @serial
- */
- private final long identity;
-
- SerializationProxy(double value,
- DoubleBinaryOperator function,
- long identity) {
- this.value = value;
- this.function = function;
- this.identity = identity;
- }
-
- /**
- * Returns a {@code DoubleAccumulator} object with initial state
- * held by this proxy.
- *
- * @return a {@code DoubleAccumulator} object with initial state
- * held by this proxy
- */
- private Object readResolve() {
- double d = Double.longBitsToDouble(identity);
- DoubleAccumulator a = new DoubleAccumulator(function, d);
- a.base = Double.doubleToRawLongBits(value);
- return a;
- }
- }
-
- /**
- * Returns a
- * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAccumulator.SerializationProxy">
- * SerializationProxy</a>
- * representing the state of this instance.
- *
- * @return a {@link SerializationProxy}
- * representing the state of this instance
- */
- private Object writeReplace() {
- return new SerializationProxy(get(), function, identity);
- }
-
- /**
- * @param s the stream
- * @throws java.io.InvalidObjectException always
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.InvalidObjectException {
- throw new java.io.InvalidObjectException("Proxy required");
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/DoubleAdder.java b/luni/src/main/java/java/util/concurrent/atomic/DoubleAdder.java
deleted file mode 100644
index 94844d5..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/DoubleAdder.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.atomic;
-
-import java.io.Serializable;
-
-/**
- * One or more variables that together maintain an initially zero
- * {@code double} sum. When updates (method {@link #add}) are
- * contended across threads, the set of variables may grow dynamically
- * to reduce contention. Method {@link #sum} (or, equivalently {@link
- * #doubleValue}) returns the current total combined across the
- * variables maintaining the sum. The order of accumulation within or
- * across threads is not guaranteed. Thus, this class may not be
- * applicable if numerical stability is required, especially when
- * combining values of substantially different orders of magnitude.
- *
- * <p>This class is usually preferable to alternatives when multiple
- * threads update a common value that is used for purposes such as
- * summary statistics that are frequently updated but less frequently
- * read.
- *
- * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code equals}, {@code hashCode} and {@code
- * compareTo} because instances are expected to be mutated, and so are
- * not useful as collection keys.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class DoubleAdder extends Striped64 implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /*
- * Note that we must use "long" for underlying representations,
- * because there is no compareAndSet for double, due to the fact
- * that the bitwise equals used in any CAS implementation is not
- * the same as double-precision equals. However, we use CAS only
- * to detect and alleviate contention, for which bitwise equals
- * works best anyway. In principle, the long/double conversions
- * used here should be essentially free on most platforms since
- * they just re-interpret bits.
- */
-
- /**
- * Creates a new adder with initial sum of zero.
- */
- public DoubleAdder() {
- }
-
- /**
- * Adds the given value.
- *
- * @param x the value to add
- */
- public void add(double x) {
- Cell[] as; long b, v; int m; Cell a;
- if ((as = cells) != null ||
- !casBase(b = base,
- Double.doubleToRawLongBits
- (Double.longBitsToDouble(b) + x))) {
- boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[getProbe() & m]) == null ||
- !(uncontended = a.cas(v = a.value,
- Double.doubleToRawLongBits
- (Double.longBitsToDouble(v) + x))))
- doubleAccumulate(x, null, uncontended);
- }
- }
-
- /**
- * Returns the current sum. The returned value is <em>NOT</em> an
- * atomic snapshot; invocation in the absence of concurrent
- * updates returns an accurate result, but concurrent updates that
- * occur while the sum is being calculated might not be
- * incorporated. Also, because floating-point arithmetic is not
- * strictly associative, the returned result need not be identical
- * to the value that would be obtained in a sequential series of
- * updates to a single variable.
- *
- * @return the sum
- */
- public double sum() {
- Cell[] as = cells;
- double sum = Double.longBitsToDouble(base);
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- sum += Double.longBitsToDouble(a.value);
- }
- return sum;
- }
-
- /**
- * Resets variables maintaining the sum to zero. This method may
- * be a useful alternative to creating a new adder, but is only
- * effective if there are no concurrent updates. Because this
- * method is intrinsically racy, it should only be used when it is
- * known that no threads are concurrently updating.
- */
- public void reset() {
- Cell[] as = cells;
- base = 0L; // relies on fact that double 0 must have same rep as long
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- a.reset();
- }
- }
-
- /**
- * Equivalent in effect to {@link #sum} followed by {@link
- * #reset}. This method may apply for example during quiescent
- * points between multithreaded computations. If there are
- * updates concurrent with this method, the returned value is
- * <em>not</em> guaranteed to be the final value occurring before
- * the reset.
- *
- * @return the sum
- */
- public double sumThenReset() {
- Cell[] as = cells;
- double sum = Double.longBitsToDouble(base);
- base = 0L;
- if (as != null) {
- for (Cell a : as) {
- if (a != null) {
- long v = a.value;
- a.reset();
- sum += Double.longBitsToDouble(v);
- }
- }
- }
- return sum;
- }
-
- /**
- * Returns the String representation of the {@link #sum}.
- * @return the String representation of the {@link #sum}
- */
- public String toString() {
- return Double.toString(sum());
- }
-
- /**
- * Equivalent to {@link #sum}.
- *
- * @return the sum
- */
- public double doubleValue() {
- return sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code long} after a
- * narrowing primitive conversion.
- */
- public long longValue() {
- return (long)sum();
- }
-
- /**
- * Returns the {@link #sum} as an {@code int} after a
- * narrowing primitive conversion.
- */
- public int intValue() {
- return (int)sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code float}
- * after a narrowing primitive conversion.
- */
- public float floatValue() {
- return (float)sum();
- }
-
- /**
- * Serialization proxy, used to avoid reference to the non-public
- * Striped64 superclass in serialized forms.
- * @serial include
- */
- private static class SerializationProxy implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * The current value returned by sum().
- * @serial
- */
- private final double value;
-
- SerializationProxy(DoubleAdder a) {
- value = a.sum();
- }
-
- /**
- * Returns a {@code DoubleAdder} object with initial state
- * held by this proxy.
- *
- * @return a {@code DoubleAdder} object with initial state
- * held by this proxy
- */
- private Object readResolve() {
- DoubleAdder a = new DoubleAdder();
- a.base = Double.doubleToRawLongBits(value);
- return a;
- }
- }
-
- /**
- * Returns a
- * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAdder.SerializationProxy">
- * SerializationProxy</a>
- * representing the state of this instance.
- *
- * @return a {@link SerializationProxy}
- * representing the state of this instance
- */
- private Object writeReplace() {
- return new SerializationProxy(this);
- }
-
- /**
- * @param s the stream
- * @throws java.io.InvalidObjectException always
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.InvalidObjectException {
- throw new java.io.InvalidObjectException("Proxy required");
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/Fences.java b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
new file mode 100644
index 0000000..d907faf
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
@@ -0,0 +1,538 @@
+/*
+ * 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.atomic;
+
+/**
+ * A set of methods providing fine-grained control over happens-before
+ * and synchronization order relations among reads and/or writes. The
+ * methods of this class are designed for use in uncommon situations
+ * where declaring variables {@code volatile} or {@code final}, using
+ * instances of atomic classes, using {@code synchronized} blocks or
+ * methods, or using other synchronization facilities are not possible
+ * or do not provide the desired control.
+ *
+ * <p><b>Memory Ordering.</b> There are three methods for controlling
+ * ordering relations among memory accesses (i.e., reads and
+ * writes). Method {@code orderWrites} is typically used to enforce
+ * order between two writes, and {@code orderAccesses} between a write
+ * and a read. Method {@code orderReads} is used to enforce order
+ * between two reads with respect to other {@code orderWrites} and/or
+ * {@code orderAccesses} invocations. The formally specified
+ * properties of these methods described below provide
+ * platform-independent guarantees that are honored by all levels of a
+ * platform (compilers, systems, processors). The use of these
+ * methods may result in the suppression of otherwise valid compiler
+ * transformations and optimizations that could visibly violate the
+ * specified orderings, and may or may not entail the use of
+ * processor-level "memory barrier" instructions.
+ *
+ * <p>Each ordering method accepts a {@code ref} argument, and
+ * controls ordering among accesses with respect to this reference.
+ * Invocations must be placed <em>between</em> accesses performed in
+ * expression evaluations and assignment statements to control the
+ * orderings of prior versus subsequent accesses appearing in program
+ * order. These methods also return their arguments to simplify
+ * correct usage in these contexts.
+ *
+ * <p>Usages of ordering methods almost always take one of the forms
+ * illustrated in the examples below. These idioms arrange some of
+ * the ordering properties associated with {@code volatile} and
+ * related language-based constructions, but without other
+ * compile-time and runtime benefits that make language-based
+ * constructions far better choices when they are applicable. Usages
+ * should be restricted to the control of strictly internal
+ * implementation matters inside a class or package, and must either
+ * avoid or document any consequent violations of ordering or safety
+ * properties expected by users of a class employing them.
+ *
+ * <p><b>Reachability.</b> Method {@code reachabilityFence}
+ * establishes an ordering for strong reachability (as defined in the
+ * {@link java.lang.ref} package specification) with respect to
+ * garbage collection. Method {@code reachabilityFence} differs from
+ * the others in that it controls relations that are otherwise only
+ * implicit in a program -- the reachability conditions triggering
+ * garbage collection. As illustrated in the sample usages below,
+ * this method is applicable only when reclamation may have visible
+ * effects, which is possible for objects with finalizers (see Section
+ * 12.6 of the Java Language Specification) that are implemented in
+ * ways that rely on ordering control for correctness.
+ *
+ * <p><b>Sample Usages</b>
+ *
+ * <p><b>Safe publication.</b> With care, method {@code orderWrites}
+ * may be used to obtain the memory safety effects of {@code final}
+ * for a field that cannot be declared as {@code final}, because its
+ * primary initialization cannot be performed in a constructor, in
+ * turn because it is used in a framework requiring that all classes
+ * have a no-argument constructor; as in:
+ *
+ * <pre> {@code
+ * class WidgetHolder {
+ * private Widget widget;
+ * public WidgetHolder() {}
+ * public static WidgetHolder newWidgetHolder(Params params) {
+ * WidgetHolder h = new WidgetHolder();
+ * h.widget = new Widget(params);
+ * return Fences.orderWrites(h);
+ * }
+ * }}</pre>
+ *
+ * Here, the invocation of {@code orderWrites} ensures that the
+ * effects of the widget assignment are ordered before those of any
+ * (unknown) subsequent stores of {@code h} in other variables that
+ * make {@code h} available for use by other objects. Initialization
+ * sequences using {@code orderWrites} require more care than those
+ * involving {@code final} fields. When {@code final} is not used,
+ * compilers cannot help you to ensure that the field is set correctly
+ * across all usages. You must fully initialize objects
+ * <em>before</em> the {@code orderWrites} invocation that makes
+ * references to them safe to assign to accessible variables. Further,
+ * initialization sequences must not internally "leak" the reference
+ * by using it as an argument to a callback method or adding it to a
+ * static data structure. If less constrained usages were required,
+ * it may be possible to cope using more extensive sets of fences, or
+ * as a normally better choice, using synchronization (locking).
+ * Conversely, if it were possible to do so, the best option would be
+ * to rewrite class {@code WidgetHolder} to use {@code final}.
+ *
+ * <p>An alternative approach is to place similar mechanics in the
+ * (sole) method that makes such objects available for use by others.
+ * Here is a stripped-down example illustrating the essentials. In
+ * practice, among other changes, you would use access methods instead
+ * of a public field.
+ *
+ * <pre> {@code
+ * class AnotherWidgetHolder {
+ * public Widget widget;
+ * void publish(Widget w) {
+ * this.widget = Fences.orderWrites(w);
+ * }
+ * // ...
+ * }}</pre>
+ *
+ * In this case, the {@code orderWrites} invocation occurs before the
+ * store making the object available. Correctness again relies on
+ * ensuring that there are no leaks prior to invoking this method, and
+ * that it really is the <em>only</em> means of accessing the
+ * published object. This approach is not often applicable --
+ * normally you would publish objects using a thread-safe collection
+ * that itself guarantees the expected ordering relations. However, it
+ * may come into play in the construction of such classes themselves.
+ *
+ * <p><b>Safely updating fields.</b> Outside of the initialization
+ * idioms illustrated above, Fence methods ordering writes must be
+ * paired with those ordering reads. To illustrate, suppose class
+ * {@code c} contains an accessible variable {@code data} that should
+ * have been declared as {@code volatile} but wasn't:
+ *
+ * <pre> {@code
+ * class C {
+ * Object data; // need volatile access but not volatile
+ * // ...
+ * }
+ *
+ * class App {
+ * Object getData(C c) {
+ * return Fences.orderReads(c).data;
+ * }
+ *
+ * void setData(C c) {
+ * Object newValue = ...;
+ * c.data = Fences.orderWrites(newValue);
+ * Fences.orderAccesses(c);
+ * }
+ * // ...
+ * }}</pre>
+ *
+ * Method {@code getData} provides an emulation of {@code volatile}
+ * reads of (non-long/double) fields by ensuring that the read of
+ * {@code c} obtained as an argument is ordered before subsequent
+ * reads using this reference, and then performs the read of its
+ * field. Method {@code setData} provides an emulation of volatile
+ * writes, ensuring that all other relevant writes have completed,
+ * then performing the assignment, and then ensuring that the write is
+ * ordered before any other access. These techniques may apply even
+ * when fields are not directly accessible, in which case calls to
+ * fence methods would surround calls to methods such as {@code
+ * c.getData()}. However, these techniques cannot be applied to
+ * {@code long} or {@code double} fields because reads and writes of
+ * fields of these types are not guaranteed to be
+ * atomic. Additionally, correctness may require that all accesses of
+ * such data use these kinds of wrapper methods, which you would need
+ * to manually ensure.
+ *
+ * <p>More generally, Fence methods can be used in this way to achieve
+ * the safety properties of {@code volatile}. However their use does
+ * not necessarily guarantee the full sequential consistency
+ * properties specified in the Java Language Specification chapter 17
+ * for programs using {@code volatile}. In particular, emulation using
+ * Fence methods is not guaranteed to maintain the property that
+ * {@code volatile} operations performed by different threads are
+ * observed in the same order by all observer threads.
+ *
+ * <p><b>Acquire/Release management of threadsafe objects</b>. It may
+ * be possible to use weaker conventions for volatile-like variables
+ * when they are used to keep track of objects that fully manage their
+ * own thread-safety and synchronization. Here, an acquiring read
+ * operation remains the same as a volatile-read, but a releasing
+ * write differs by virtue of not itself ensuring an ordering of its
+ * write with subsequent reads, because the required effects are
+ * already ensured by the referenced objects.
+ * For example:
+ *
+ * <pre> {@code
+ * class Item {
+ * synchronized f(); // ALL methods are synchronized
+ * // ...
+ * }
+ *
+ * class ItemHolder {
+ * private Item item;
+ * Item acquireItem() {
+ * return Fences.orderReads(item);
+ * }
+ *
+ * void releaseItem(Item x) {
+ * item = Fences.orderWrites(x);
+ * }
+ *
+ * // ...
+ * }}</pre>
+ *
+ * Because this construction avoids use of {@code orderAccesses},
+ * which is typically more costly than the other fence methods, it may
+ * result in better performance than using {@code volatile} or its
+ * emulation. However, as is the case with most applications of fence
+ * methods, correctness relies on the usage context -- here, the
+ * thread safety of {@code Item}, as well as the lack of need for full
+ * volatile semantics inside this class itself. However, the second
+ * concern means that it can be difficult to extend the {@code
+ * ItemHolder} class in this example to be more useful.
+ *
+ * <p><b>Avoiding premature finalization.</b> Finalization may occur
+ * whenever a Java Virtual Machine detects that no reference to an
+ * object will ever be stored in the heap: A garbage collector may
+ * reclaim an object even if the fields of that object are still in
+ * use, so long as the object has otherwise become unreachable. This
+ * may have surprising and undesirable effects in cases such as the
+ * following example in which the bookkeeping associated with a class
+ * is managed through array indices. Here, method {@code action}
+ * uses a {@code reachabilityFence} to ensure that the Resource
+ * object is not reclaimed before bookkeeping on an associated
+ * ExternalResource has been performed; in particular here, to ensure
+ * that the array slot holding the ExternalResource is not nulled out
+ * in method {@link Object#finalize}, which may otherwise run
+ * concurrently.
+ *
+ * <pre> {@code
+ * class Resource {
+ * private static ExternalResource[] externalResourceArray = ...
+ *
+ * int myIndex;
+ * Resource(...) {
+ * myIndex = ...
+ * externalResourceArray[myIndex] = ...;
+ * ...
+ * }
+ * protected void finalize() {
+ * externalResourceArray[myIndex] = null;
+ * ...
+ * }
+ * public void action() {
+ * try {
+ * // ...
+ * int i = myIndex;
+ * Resource.update(externalResourceArray[i]);
+ * } finally {
+ * Fences.reachabilityFence(this);
+ * }
+ * }
+ * private static void update(ExternalResource ext) {
+ * ext.status = ...;
+ * }
+ * }}</pre>
+ *
+ * Here, the call to {@code reachabilityFence} is nonintuitively
+ * placed <em>after</em> the call to {@code update}, to ensure that
+ * the array slot is not nulled out by {@link Object#finalize} before
+ * the update, even if the call to {@code action} was the last use of
+ * this object. This might be the case if for example a usage in a
+ * user program had the form {@code new Resource().action();} which
+ * retains no other reference to this Resource. While probably
+ * overkill here, {@code reachabilityFence} is placed in a {@code
+ * finally} block to ensure that it is invoked across all paths in the
+ * method. In a method with more complex control paths, you might
+ * need further precautions to ensure that {@code reachabilityFence}
+ * is encountered along all of them.
+ *
+ * <p>It is sometimes possible to better encapsulate use of
+ * {@code reachabilityFence}. Continuing the above example, if it
+ * were OK for the call to method update to proceed even if the
+ * finalizer had already executed (nulling out slot), then you could
+ * localize use of {@code reachabilityFence}:
+ *
+ * <pre> {@code
+ * public void action2() {
+ * // ...
+ * Resource.update(getExternalResource());
+ * }
+ * private ExternalResource getExternalResource() {
+ * ExternalResource ext = externalResourceArray[myIndex];
+ * Fences.reachabilityFence(this);
+ * return ext;
+ * }}</pre>
+ *
+ * <p>Method {@code reachabilityFence} is not required in
+ * constructions that themselves ensure reachability. For example,
+ * because objects that are locked cannot in general be reclaimed, it
+ * would suffice if all accesses of the object, in all methods of
+ * class Resource (including {@code finalize}) were enclosed in {@code
+ * synchronized (this)} blocks. (Further, such blocks must not include
+ * infinite loops, or themselves be unreachable, which fall into the
+ * corner case exceptions to the "in general" disclaimer.) However,
+ * method {@code reachabilityFence} remains a better option in cases
+ * where this approach is not as efficient, desirable, or possible;
+ * for example because it would encounter deadlock.
+ *
+ * <p><b>Formal Properties.</b>
+ *
+ * <p>Using the terminology of The Java Language Specification chapter
+ * 17, the rules governing the semantics of the methods of this class
+ * are as follows:
+ *
+ * <p>The following is still under construction.
+ *
+ * <dl>
+ *
+ * <dt><b>[Definitions]</b>
+ * <dd>
+ * <ul>
+ *
+ * <li>Define <em>sequenced(a, b)</em> to be true if <em>a</em>
+ * occurs before <em>b</em> in <em>program order</em>.
+ *
+ * <li>Define <em>accesses(a, p)</em> to be true if
+ * <em>a</em> is a read or write of a field (or if an array, an
+ * element) of the object referenced by <em>p</em>.
+ *
+ * <li>Define <em>deeplyAccesses(a, p)</em> to be true if either
+ * <em>accesses(a, p)</em> or <em>deeplyAccesses(a, q)</em> where
+ * <em>q</em> is the value seen by some read <em>r</em>
+ * such that <em>accesses(r, p)</em>.
+ *
+ * </ul>
+ * <dt><b>[Matching]</b>
+ * <dd>Given:
+ *
+ * <ul>
+ *
+ * <li><em>p</em>, a reference to an object
+ *
+ * <li><em>wf</em>, an invocation of {@code orderWrites(p)} or
+ * {@code orderAccesses(p)}
+ *
+ * <li><em>w</em>, a write of value <em>p</em>
+ *
+ * <li> <em>rf</em>, an invocation of {@code orderReads(p)} or
+ * {@code orderAccesses(p)}
+ *
+ * <li> <em>r</em>, a read returning value <em>p</em>
+ *
+ * </ul>
+ * If:
+ * <ul>
+ * <li>sequenced(wf, w)
+ * <li>read <em>r</em> sees write <em>w</em>
+ * <li>sequenced(r, rf)
+ * </ul>
+ * Then:
+ * <ul>
+ *
+ * <li> <em>wf happens-before rf</em>
+ *
+ * <li> <em>wf</em> precedes <em>rf</em> in the
+ * <em>synchronization order</em>
+ *
+ * <li> If (<em>r1</em>, <em>w1</em>) and (<em>r2</em>,
+ * <em>w2</em>) are two pairs of reads and writes, both
+ * respectively satisfying the above conditions for <em>p</em>,
+ * and sequenced(r1, r2) then it is not the case that <em>w2
+ * happens-before w1</em>.
+ *
+ * </ul>
+ * <dt><b>[Initial Reads]</b>
+ * <dd>Given:
+ *
+ * <ul>
+ *
+ * <li><em>p</em>, a reference to an object
+ *
+ * <li> <em>a</em>, an access where deeplyAccesses(a, p)
+ *
+ * <li><em>wf</em>, an invocation of {@code orderWrites(p)} or
+ * {@code orderAccesses(p)}
+ *
+ * <li><em>w</em>, a write of value <em>p</em>
+ *
+ * <li> <em>r</em>, a read returning value <em>p</em>
+ *
+ * <li> <em>b</em>, an access where accesses(b, p)
+ *
+ * </ul>
+ * If:
+ * <ul>
+ * <li>sequenced(a, wf);
+ * <li>sequenced(wf, w)
+ * <li>read <em>r</em> sees write <em>w</em>, and
+ * <em>r</em> is the first read by some thread
+ * <em>t</em> that sees value <em>p</em>
+ * <li>sequenced(r, b)
+ * </ul>
+ * Then:
+ * <ul>
+ * <li> the effects of <em>b</em> are constrained
+ * by the relation <em>a happens-before b</em>.
+ * </ul>
+ * <dt><b>[orderAccesses]</b>
+ * <dd>Given:
+ *
+ * <ul>
+ * <li><em>p</em>, a reference to an object
+ * <li><em>f</em>, an invocation of {@code orderAccesses(p)}
+ * </ul>
+ * If:
+ * <ul>
+ * <li>sequenced(f, w)
+ * </ul>
+ *
+ * Then:
+ *
+ * <ul>
+ *
+ * <li> <em>f</em> is an element of the <em>synchronization order</em>.
+ *
+ * </ul>
+ * <dt><b>[Reachability]</b>
+ * <dd>Given:
+ *
+ * <ul>
+ *
+ * <li><em>p</em>, a reference to an object
+ *
+ * <li><em>f</em>, an invocation of {@code reachabilityFence(p)}
+ *
+ * <li><em>a</em>, an access where accesses(a, p)
+ *
+ * <li><em>b</em>, an action (by a garbage collector) taking
+ * the form of an invocation of {@code
+ * p.finalize()} or of enqueuing any {@link
+ * java.lang.ref.Reference} constructed with argument <em>p</em>
+ *
+ * </ul>
+ *
+ * If:
+ * <ul>
+ * <li>sequenced(a, f)
+ * </ul>
+ *
+ * Then:
+ *
+ * <ul>
+ *
+ * <li> <em>a happens-before b</em>.
+ *
+ * </ul>
+ *
+ * </dl>
+ *
+ * @hide
+ * @author Doug Lea
+ */
+public class Fences {
+ private Fences() {} // Non-instantiable
+
+ /**
+ * The methods of this class are intended to be intrinisified by a
+ * JVM. However, we provide correct but inefficient Java-level
+ * code that simply reads and writes a static volatile
+ * variable. Without JVM support, the consistency effects are
+ * stronger than necessary, and the memory contention effects can
+ * be a serious performance issue.
+ */
+ private static volatile int theVolatile;
+
+ /**
+ * Informally: Ensures that a read of the given reference prior to
+ * the invocation of this method occurs before a subsequent use of
+ * the given reference with the effect of reading or writing a
+ * field (or if an array, element) of the referenced object. The
+ * use of this method is sensible only when paired with other
+ * invocations of {@link #orderWrites} and/or {@link
+ * #orderAccesses} for the given reference. For details, see the
+ * class documentation for this class.
+ *
+ * @param ref the reference. If null, this method has no effect.
+ * @param <T> the type of the reference
+ * @return the given ref, to simplify usage
+ */
+ public static <T> T orderReads(T ref) {
+ int ignore = theVolatile;
+ return ref;
+ }
+
+ /**
+ * Informally: Ensures that a use of the given reference with the
+ * effect of reading or writing a field (or if an array, element)
+ * of the referenced object, prior to the invocation of this
+ * method occur before a subsequent write of the reference. For
+ * details, see the class documentation for this class.
+ *
+ * @param ref the reference. If null, this method has no effect.
+ * @param <T> the type of the reference
+ * @return the given ref, to simplify usage
+ */
+ public static <T> T orderWrites(T ref) {
+ theVolatile = 0;
+ return ref;
+ }
+
+ /**
+ * Informally: Ensures that accesses (reads or writes) using the
+ * given reference prior to the invocation of this method occur
+ * before subsequent accesses. For details, see the class
+ * documentation for this class.
+ *
+ * @param ref the reference. If null, this method has no effect.
+ * @param <T> the type of the reference
+ * @return the given ref, to simplify usage
+ */
+ public static <T> T orderAccesses(T ref) {
+ theVolatile = 0;
+ return ref;
+ }
+
+ /**
+ * Ensures that the object referenced by the given reference
+ * remains <em>strongly reachable</em> (as defined in the {@link
+ * java.lang.ref} package documentation), regardless of any prior
+ * actions of the program that might otherwise cause the object to
+ * become unreachable; thus, the referenced object is not
+ * reclaimable by garbage collection at least until after the
+ * invocation of this method. Invocation of this method does not
+ * itself initiate garbage collection or finalization.
+ *
+ * <p>See the class-level documentation for further explanation
+ * and usage examples.
+ *
+ * @param ref the reference. If null, this method has no effect.
+ */
+ public static void reachabilityFence(Object ref) {
+ if (ref != null) {
+ synchronized (ref) {}
+ }
+ }
+}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/LongAccumulator.java b/luni/src/main/java/java/util/concurrent/atomic/LongAccumulator.java
deleted file mode 100644
index 85e3241..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/LongAccumulator.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * 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.atomic;
-
-import java.io.Serializable;
-import java.util.function.LongBinaryOperator;
-
-/**
- * One or more variables that together maintain a running {@code long}
- * value updated using a supplied function. When updates (method
- * {@link #accumulate}) are contended across threads, the set of variables
- * may grow dynamically to reduce contention. Method {@link #get}
- * (or, equivalently, {@link #longValue}) returns the current value
- * across the variables maintaining updates.
- *
- * <p>This class is usually preferable to {@link AtomicLong} when
- * multiple threads update a common value that is used for purposes such
- * as collecting statistics, not for fine-grained synchronization
- * control. Under low update contention, the two classes have similar
- * characteristics. But under high contention, expected throughput of
- * this class is significantly higher, at the expense of higher space
- * consumption.
- *
- * <p>The order of accumulation within or across threads is not
- * guaranteed and cannot be depended upon, so this class is only
- * applicable to functions for which the order of accumulation does
- * not matter. The supplied accumulator 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. For example, to maintain a running maximum
- * value, you could supply {@code Long::max} along with {@code
- * Long.MIN_VALUE} as the identity.
- *
- * <p>Class {@link LongAdder} provides analogs of the functionality of
- * this class for the common special case of maintaining counts and
- * sums. The call {@code new LongAdder()} is equivalent to {@code new
- * LongAccumulator((x, y) -> x + y, 0L}.
- *
- * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code equals}, {@code hashCode} and {@code
- * compareTo} because instances are expected to be mutated, and so are
- * not useful as collection keys.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class LongAccumulator extends Striped64 implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- private final LongBinaryOperator function;
- private final long identity;
-
- /**
- * Creates a new instance using the given accumulator function
- * and identity element.
- * @param accumulatorFunction a side-effect-free function of two arguments
- * @param identity identity (initial value) for the accumulator function
- */
- public LongAccumulator(LongBinaryOperator accumulatorFunction,
- long identity) {
- this.function = accumulatorFunction;
- base = this.identity = identity;
- }
-
- /**
- * Updates with the given value.
- *
- * @param x the value
- */
- public void accumulate(long x) {
- Cell[] as; long b, v, r; int m; Cell a;
- if ((as = cells) != null ||
- (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {
- boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[getProbe() & m]) == null ||
- !(uncontended =
- (r = function.applyAsLong(v = a.value, x)) == v ||
- a.cas(v, r)))
- longAccumulate(x, function, uncontended);
- }
- }
-
- /**
- * Returns the current value. The returned value is <em>NOT</em>
- * an atomic snapshot; invocation in the absence of concurrent
- * updates returns an accurate result, but concurrent updates that
- * occur while the value is being calculated might not be
- * incorporated.
- *
- * @return the current value
- */
- public long get() {
- Cell[] as = cells;
- long result = base;
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- result = function.applyAsLong(result, a.value);
- }
- return result;
- }
-
- /**
- * Resets variables maintaining updates to the identity value.
- * This method may be a useful alternative to creating a new
- * updater, but is only effective if there are no concurrent
- * updates. Because this method is intrinsically racy, it should
- * only be used when it is known that no threads are concurrently
- * updating.
- */
- public void reset() {
- Cell[] as = cells;
- base = identity;
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- a.reset(identity);
- }
- }
-
- /**
- * Equivalent in effect to {@link #get} followed by {@link
- * #reset}. This method may apply for example during quiescent
- * points between multithreaded computations. If there are
- * updates concurrent with this method, the returned value is
- * <em>not</em> guaranteed to be the final value occurring before
- * the reset.
- *
- * @return the value before reset
- */
- public long getThenReset() {
- Cell[] as = cells;
- long result = base;
- base = identity;
- if (as != null) {
- for (Cell a : as) {
- if (a != null) {
- long v = a.value;
- a.reset(identity);
- result = function.applyAsLong(result, v);
- }
- }
- }
- return result;
- }
-
- /**
- * Returns the String representation of the current value.
- * @return the String representation of the current value
- */
- public String toString() {
- return Long.toString(get());
- }
-
- /**
- * Equivalent to {@link #get}.
- *
- * @return the current value
- */
- public long longValue() {
- return get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as an {@code int}
- * after a narrowing primitive conversion.
- */
- public int intValue() {
- return (int)get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as a {@code float}
- * after a widening primitive conversion.
- */
- public float floatValue() {
- return (float)get();
- }
-
- /**
- * Returns the {@linkplain #get current value} as a {@code double}
- * after a widening primitive conversion.
- */
- public double doubleValue() {
- return (double)get();
- }
-
- /**
- * Serialization proxy, used to avoid reference to the non-public
- * Striped64 superclass in serialized forms.
- * @serial include
- */
- private static class SerializationProxy implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * The current value returned by get().
- * @serial
- */
- private final long value;
-
- /**
- * The function used for updates.
- * @serial
- */
- private final LongBinaryOperator function;
-
- /**
- * The identity value.
- * @serial
- */
- private final long identity;
-
- SerializationProxy(long value,
- LongBinaryOperator function,
- long identity) {
- this.value = value;
- this.function = function;
- this.identity = identity;
- }
-
- /**
- * Returns a {@code LongAccumulator} object with initial state
- * held by this proxy.
- *
- * @return a {@code LongAccumulator} object with initial state
- * held by this proxy
- */
- private Object readResolve() {
- LongAccumulator a = new LongAccumulator(function, identity);
- a.base = value;
- return a;
- }
- }
-
- /**
- * Returns a
- * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
- * SerializationProxy</a>
- * representing the state of this instance.
- *
- * @return a {@link SerializationProxy}
- * representing the state of this instance
- */
- private Object writeReplace() {
- return new SerializationProxy(get(), function, identity);
- }
-
- /**
- * @param s the stream
- * @throws java.io.InvalidObjectException always
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.InvalidObjectException {
- throw new java.io.InvalidObjectException("Proxy required");
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/LongAdder.java b/luni/src/main/java/java/util/concurrent/atomic/LongAdder.java
deleted file mode 100644
index a17d52a..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/LongAdder.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * 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.atomic;
-
-import java.io.Serializable;
-
-/**
- * One or more variables that together maintain an initially zero
- * {@code long} sum. When updates (method {@link #add}) are contended
- * across threads, the set of variables may grow dynamically to reduce
- * contention. Method {@link #sum} (or, equivalently, {@link
- * #longValue}) returns the current total combined across the
- * variables maintaining the sum.
- *
- * <p>This class is usually preferable to {@link AtomicLong} when
- * multiple threads update a common sum that is used for purposes such
- * as collecting statistics, not for fine-grained synchronization
- * control. Under low update contention, the two classes have similar
- * characteristics. But under high contention, expected throughput of
- * this class is significantly higher, at the expense of higher space
- * consumption.
- *
- * <p>LongAdders can be used with a {@link
- * java.util.concurrent.ConcurrentHashMap} to maintain a scalable
- * frequency map (a form of histogram or multiset). For example, to
- * add a count to a {@code ConcurrentHashMap<String,LongAdder> freqs},
- * initializing if not already present, you can use {@code
- * freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
- *
- * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code equals}, {@code hashCode} and {@code
- * compareTo} because instances are expected to be mutated, and so are
- * not useful as collection keys.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class LongAdder extends Striped64 implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * Creates a new adder with initial sum of zero.
- */
- public LongAdder() {
- }
-
- /**
- * Adds the given value.
- *
- * @param x the value to add
- */
- public void add(long x) {
- Cell[] as; long b, v; int m; Cell a;
- if ((as = cells) != null || !casBase(b = base, b + x)) {
- boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[getProbe() & m]) == null ||
- !(uncontended = a.cas(v = a.value, v + x)))
- longAccumulate(x, null, uncontended);
- }
- }
-
- /**
- * Equivalent to {@code add(1)}.
- */
- public void increment() {
- add(1L);
- }
-
- /**
- * Equivalent to {@code add(-1)}.
- */
- public void decrement() {
- add(-1L);
- }
-
- /**
- * Returns the current sum. The returned value is <em>NOT</em> an
- * atomic snapshot; invocation in the absence of concurrent
- * updates returns an accurate result, but concurrent updates that
- * occur while the sum is being calculated might not be
- * incorporated.
- *
- * @return the sum
- */
- public long sum() {
- Cell[] as = cells;
- long sum = base;
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- sum += a.value;
- }
- return sum;
- }
-
- /**
- * Resets variables maintaining the sum to zero. This method may
- * be a useful alternative to creating a new adder, but is only
- * effective if there are no concurrent updates. Because this
- * method is intrinsically racy, it should only be used when it is
- * known that no threads are concurrently updating.
- */
- public void reset() {
- Cell[] as = cells;
- base = 0L;
- if (as != null) {
- for (Cell a : as)
- if (a != null)
- a.reset();
- }
- }
-
- /**
- * Equivalent in effect to {@link #sum} followed by {@link
- * #reset}. This method may apply for example during quiescent
- * points between multithreaded computations. If there are
- * updates concurrent with this method, the returned value is
- * <em>not</em> guaranteed to be the final value occurring before
- * the reset.
- *
- * @return the sum
- */
- public long sumThenReset() {
- Cell[] as = cells;
- long sum = base;
- base = 0L;
- if (as != null) {
- for (Cell a : as) {
- if (a != null) {
- sum += a.value;
- a.reset();
- }
- }
- }
- return sum;
- }
-
- /**
- * Returns the String representation of the {@link #sum}.
- * @return the String representation of the {@link #sum}
- */
- public String toString() {
- return Long.toString(sum());
- }
-
- /**
- * Equivalent to {@link #sum}.
- *
- * @return the sum
- */
- public long longValue() {
- return sum();
- }
-
- /**
- * Returns the {@link #sum} as an {@code int} after a narrowing
- * primitive conversion.
- */
- public int intValue() {
- return (int)sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code float}
- * after a widening primitive conversion.
- */
- public float floatValue() {
- return (float)sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code double} after a widening
- * primitive conversion.
- */
- public double doubleValue() {
- return (double)sum();
- }
-
- /**
- * Serialization proxy, used to avoid reference to the non-public
- * Striped64 superclass in serialized forms.
- * @serial include
- */
- private static class SerializationProxy implements Serializable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * The current value returned by sum().
- * @serial
- */
- private final long value;
-
- SerializationProxy(LongAdder a) {
- value = a.sum();
- }
-
- /**
- * Returns a {@code LongAdder} object with initial state
- * held by this proxy.
- *
- * @return a {@code LongAdder} object with initial state
- * held by this proxy
- */
- private Object readResolve() {
- LongAdder a = new LongAdder();
- a.base = value;
- return a;
- }
- }
-
- /**
- * Returns a
- * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAdder.SerializationProxy">
- * SerializationProxy</a>
- * representing the state of this instance.
- *
- * @return a {@link SerializationProxy}
- * representing the state of this instance
- */
- private Object writeReplace() {
- return new SerializationProxy(this);
- }
-
- /**
- * @param s the stream
- * @throws java.io.InvalidObjectException always
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.InvalidObjectException {
- throw new java.io.InvalidObjectException("Proxy required");
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/Striped64.java b/luni/src/main/java/java/util/concurrent/atomic/Striped64.java
deleted file mode 100644
index fc88849..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/Striped64.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * 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.atomic;
-
-import java.util.Arrays;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.function.DoubleBinaryOperator;
-import java.util.function.LongBinaryOperator;
-
-/**
- * A package-local class holding common representation and mechanics
- * for classes supporting dynamic striping on 64bit values. The class
- * extends Number so that concrete subclasses must publicly do so.
- */
-@SuppressWarnings("serial")
-abstract class Striped64 extends Number {
- /*
- * This class maintains a lazily-initialized table of atomically
- * updated variables, plus an extra "base" field. The table size
- * is a power of two. Indexing uses masked per-thread hash codes.
- * Nearly all declarations in this class are package-private,
- * accessed directly by subclasses.
- *
- * Table entries are of class Cell; a variant of AtomicLong padded
- * (via @Contended) to reduce cache contention. Padding is
- * overkill for most Atomics because they are usually irregularly
- * scattered in memory and thus don't interfere much with each
- * other. But Atomic objects residing in arrays will tend to be
- * placed adjacent to each other, and so will most often share
- * cache lines (with a huge negative performance impact) without
- * this precaution.
- *
- * In part because Cells are relatively large, we avoid creating
- * them until they are needed. When there is no contention, all
- * updates are made to the base field. Upon first contention (a
- * failed CAS on base update), the table is initialized to size 2.
- * The table size is doubled upon further contention until
- * reaching the nearest power of two greater than or equal to the
- * number of CPUS. Table slots remain empty (null) until they are
- * needed.
- *
- * A single spinlock ("cellsBusy") is used for initializing and
- * resizing the table, as well as populating slots with new Cells.
- * There is no need for a blocking lock; when the lock is not
- * available, threads try other slots (or the base). During these
- * retries, there is increased contention and reduced locality,
- * which is still better than alternatives.
- *
- * The Thread probe fields maintained via ThreadLocalRandom serve
- * as per-thread hash codes. We let them remain uninitialized as
- * zero (if they come in this way) until they contend at slot
- * 0. They are then initialized to values that typically do not
- * often conflict with others. Contention and/or table collisions
- * are indicated by failed CASes when performing an update
- * operation. Upon a collision, if the table size is less than
- * the capacity, it is doubled in size unless some other thread
- * holds the lock. If a hashed slot is empty, and lock is
- * available, a new Cell is created. Otherwise, if the slot
- * exists, a CAS is tried. Retries proceed by "double hashing",
- * using a secondary hash (Marsaglia XorShift) to try to find a
- * free slot.
- *
- * The table size is capped because, when there are more threads
- * than CPUs, supposing that each thread were bound to a CPU,
- * there would exist a perfect hash function mapping threads to
- * slots that eliminates collisions. When we reach capacity, we
- * search for this mapping by randomly varying the hash codes of
- * colliding threads. Because search is random, and collisions
- * only become known via CAS failures, convergence can be slow,
- * and because threads are typically not bound to CPUS forever,
- * may not occur at all. However, despite these limitations,
- * observed contention rates are typically low in these cases.
- *
- * It is possible for a Cell to become unused when threads that
- * once hashed to it terminate, as well as in the case where
- * doubling the table causes no thread to hash to it under
- * expanded mask. We do not try to detect or remove such cells,
- * under the assumption that for long-running instances, observed
- * contention levels will recur, so the cells will eventually be
- * needed again; and for short-lived ones, it does not matter.
- */
-
- /**
- * Padded variant of AtomicLong supporting only raw accesses plus CAS.
- *
- * JVM intrinsics note: It would be possible to use a release-only
- * form of CAS here, if it were provided.
- */
- // @jdk.internal.vm.annotation.Contended // android-removed
- static final class Cell {
- volatile long value;
- Cell(long x) { value = x; }
- final boolean cas(long cmp, long val) {
- return U.compareAndSwapLong(this, VALUE, cmp, val);
- }
- final void reset() {
- U.putLongVolatile(this, VALUE, 0L);
- }
- final void reset(long identity) {
- U.putLongVolatile(this, VALUE, identity);
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
- static {
- try {
- VALUE = U.objectFieldOffset
- (Cell.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
- }
-
- /** Number of CPUS, to place bound on table size */
- static final int NCPU = Runtime.getRuntime().availableProcessors();
-
- /**
- * Table of cells. When non-null, size is a power of 2.
- */
- transient volatile Cell[] cells;
-
- /**
- * Base value, used mainly when there is no contention, but also as
- * a fallback during table initialization races. Updated via CAS.
- */
- transient volatile long base;
-
- /**
- * Spinlock (locked via CAS) used when resizing and/or creating Cells.
- */
- transient volatile int cellsBusy;
-
- /**
- * Package-private default constructor.
- */
- Striped64() {
- }
-
- /**
- * CASes the base field.
- */
- final boolean casBase(long cmp, long val) {
- return U.compareAndSwapLong(this, BASE, cmp, val);
- }
-
- /**
- * CASes the cellsBusy field from 0 to 1 to acquire lock.
- */
- final boolean casCellsBusy() {
- return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
- }
-
- /**
- * Returns the probe value for the current thread.
- * Duplicated from ThreadLocalRandom because of packaging restrictions.
- */
- static final int getProbe() {
- return U.getInt(Thread.currentThread(), PROBE);
- }
-
- /**
- * Pseudo-randomly advances and records the given probe value for the
- * given thread.
- * Duplicated from ThreadLocalRandom because of packaging restrictions.
- */
- static final int advanceProbe(int probe) {
- probe ^= probe << 13; // xorshift
- probe ^= probe >>> 17;
- probe ^= probe << 5;
- U.putInt(Thread.currentThread(), PROBE, probe);
- return probe;
- }
-
- /**
- * Handles cases of updates involving initialization, resizing,
- * creating new Cells, and/or contention. See above for
- * explanation. This method suffers the usual non-modularity
- * problems of optimistic retry code, relying on rechecked sets of
- * reads.
- *
- * @param x the value
- * @param fn the update function, or null for add (this convention
- * avoids the need for an extra field or function in LongAdder).
- * @param wasUncontended false if CAS failed before call
- */
- final void longAccumulate(long x, LongBinaryOperator fn,
- boolean wasUncontended) {
- int h;
- if ((h = getProbe()) == 0) {
- ThreadLocalRandom.current(); // force initialization
- h = getProbe();
- wasUncontended = true;
- }
- boolean collide = false; // True if last slot nonempty
- done: for (;;) {
- Cell[] as; Cell a; int n; long v;
- if ((as = cells) != null && (n = as.length) > 0) {
- if ((a = as[(n - 1) & h]) == null) {
- if (cellsBusy == 0) { // Try to attach new Cell
- Cell r = new Cell(x); // Optimistically create
- if (cellsBusy == 0 && casCellsBusy()) {
- try { // Recheck under lock
- Cell[] rs; int m, j;
- if ((rs = cells) != null &&
- (m = rs.length) > 0 &&
- rs[j = (m - 1) & h] == null) {
- rs[j] = r;
- break done;
- }
- } finally {
- cellsBusy = 0;
- }
- continue; // Slot is now non-empty
- }
- }
- collide = false;
- }
- else if (!wasUncontended) // CAS already known to fail
- wasUncontended = true; // Continue after rehash
- else if (a.cas(v = a.value,
- (fn == null) ? v + x : fn.applyAsLong(v, x)))
- break;
- else if (n >= NCPU || cells != as)
- collide = false; // At max size or stale
- else if (!collide)
- collide = true;
- else if (cellsBusy == 0 && casCellsBusy()) {
- try {
- if (cells == as) // Expand table unless stale
- cells = Arrays.copyOf(as, n << 1);
- } finally {
- cellsBusy = 0;
- }
- collide = false;
- continue; // Retry with expanded table
- }
- h = advanceProbe(h);
- }
- else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
- try { // Initialize table
- if (cells == as) {
- Cell[] rs = new Cell[2];
- rs[h & 1] = new Cell(x);
- cells = rs;
- break done;
- }
- } finally {
- cellsBusy = 0;
- }
- }
- // Fall back on using base
- else if (casBase(v = base,
- (fn == null) ? v + x : fn.applyAsLong(v, x)))
- break done;
- }
- }
-
- private static long apply(DoubleBinaryOperator fn, long v, double x) {
- double d = Double.longBitsToDouble(v);
- d = (fn == null) ? d + x : fn.applyAsDouble(d, x);
- return Double.doubleToRawLongBits(d);
- }
-
- /**
- * Same as longAccumulate, but injecting long/double conversions
- * in too many places to sensibly merge with long version, given
- * the low-overhead requirements of this class. So must instead be
- * maintained by copy/paste/adapt.
- */
- final void doubleAccumulate(double x, DoubleBinaryOperator fn,
- boolean wasUncontended) {
- int h;
- if ((h = getProbe()) == 0) {
- ThreadLocalRandom.current(); // force initialization
- h = getProbe();
- wasUncontended = true;
- }
- boolean collide = false; // True if last slot nonempty
- done: for (;;) {
- Cell[] as; Cell a; int n; long v;
- if ((as = cells) != null && (n = as.length) > 0) {
- if ((a = as[(n - 1) & h]) == null) {
- if (cellsBusy == 0) { // Try to attach new Cell
- Cell r = new Cell(Double.doubleToRawLongBits(x));
- if (cellsBusy == 0 && casCellsBusy()) {
- try { // Recheck under lock
- Cell[] rs; int m, j;
- if ((rs = cells) != null &&
- (m = rs.length) > 0 &&
- rs[j = (m - 1) & h] == null) {
- rs[j] = r;
- break done;
- }
- } finally {
- cellsBusy = 0;
- }
- continue; // Slot is now non-empty
- }
- }
- collide = false;
- }
- else if (!wasUncontended) // CAS already known to fail
- wasUncontended = true; // Continue after rehash
- else if (a.cas(v = a.value, apply(fn, v, x)))
- break;
- else if (n >= NCPU || cells != as)
- collide = false; // At max size or stale
- else if (!collide)
- collide = true;
- else if (cellsBusy == 0 && casCellsBusy()) {
- try {
- if (cells == as) // Expand table unless stale
- cells = Arrays.copyOf(as, n << 1);
- } finally {
- cellsBusy = 0;
- }
- collide = false;
- continue; // Retry with expanded table
- }
- h = advanceProbe(h);
- }
- else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
- try { // Initialize table
- if (cells == as) {
- Cell[] rs = new Cell[2];
- rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
- cells = rs;
- break done;
- }
- } finally {
- cellsBusy = 0;
- }
- }
- // Fall back on using base
- else if (casBase(v = base, apply(fn, v, x)))
- break done;
- }
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long BASE;
- private static final long CELLSBUSY;
- private static final long PROBE;
- static {
- try {
- BASE = U.objectFieldOffset
- (Striped64.class.getDeclaredField("base"));
- CELLSBUSY = U.objectFieldOffset
- (Striped64.class.getDeclaredField("cellsBusy"));
-
- PROBE = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocalRandomProbe"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/package-info.java b/luni/src/main/java/java/util/concurrent/atomic/package-info.java
index b19dd49..568d2c6 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/package-info.java
@@ -11,7 +11,7 @@
* array elements to those that also provide an atomic conditional update
* operation of the form:
*
- * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
+ * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
*
* <p>This method (which varies in argument types across different
* classes) atomically sets a variable to the {@code updateValue} if it
@@ -38,7 +38,7 @@
* {@code AtomicInteger} provide atomic increment methods. One
* application is to generate sequence numbers, as in:
*
- * <pre> {@code
+ * <pre> {@code
* class Sequencer {
* private final AtomicLong sequenceNumber
* = new AtomicLong(0);
@@ -53,31 +53,31 @@
* <pre> {@code long transform(long input)}</pre>
*
* write your utility method as follows:
- * <pre> {@code
+ * <pre> {@code
* long getAndTransform(AtomicLong var) {
- * long prev, next;
- * do {
- * prev = var.get();
- * next = transform(prev);
- * } while (!var.compareAndSet(prev, next));
- * return prev; // return next; for transformAndGet
+ * while (true) {
+ * long current = var.get();
+ * long next = transform(current);
+ * if (var.compareAndSet(current, next))
+ * return current;
+ * // return next; for transformAndGet
+ * }
* }}</pre>
*
* <p>The memory effects for accesses and updates of atomics generally
* follow the rules for volatiles, as stated in
- * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
- * Chapter 17 of
- * <cite>The Java™ Language Specification</cite></a>:
+ * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4">
+ * The Java Language Specification (17.4 Memory Model)</a>:
*
* <ul>
*
- * <li>{@code get} has the memory effects of reading a
+ * <li> {@code get} has the memory effects of reading a
* {@code volatile} variable.
*
- * <li>{@code set} has the memory effects of writing (assigning) a
+ * <li> {@code set} has the memory effects of writing (assigning) a
* {@code volatile} variable.
*
- * <li>{@code lazySet} has the memory effects of writing (assigning)
+ * <li> {@code lazySet} has the memory effects of writing (assigning)
* a {@code volatile} variable except that it permits reorderings with
* subsequent (but not previous) memory actions that do not themselves
* impose reordering constraints with ordinary non-{@code volatile}
@@ -91,7 +91,7 @@
* with respect to previous or subsequent reads and writes of any
* variables other than the target of the {@code weakCompareAndSet}.
*
- * <li>{@code compareAndSet}
+ * <li> {@code compareAndSet}
* and all other read-and-update operations such as {@code getAndIncrement}
* have the memory effects of both reading and
* writing {@code volatile} variables.
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 3c10805..a74fb24 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -6,11 +6,11 @@
package java.util.concurrent.locks;
+import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+import sun.misc.Unsafe;
/**
* A version of {@link AbstractQueuedSynchronizer} in
@@ -49,6 +49,221 @@
protected AbstractQueuedLongSynchronizer() { }
/**
+ * Wait queue node class.
+ *
+ * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+ * Hagersten) lock queue. CLH locks are normally used for
+ * spinlocks. We instead use them for blocking synchronizers, but
+ * use the same basic tactic of holding some of the control
+ * information about a thread in the predecessor of its node. A
+ * "status" field in each node keeps track of whether a thread
+ * should block. A node is signalled when its predecessor
+ * releases. Each node of the queue otherwise serves as a
+ * specific-notification-style monitor holding a single waiting
+ * thread. The status field does NOT control whether threads are
+ * granted locks etc though. A thread may try to acquire if it is
+ * first in the queue. But being first does not guarantee success;
+ * it only gives the right to contend. So the currently released
+ * contender thread may need to rewait.
+ *
+ * <p>To enqueue into a CLH lock, you atomically splice it in as new
+ * tail. To dequeue, you just set the head field.
+ * <pre>
+ * +------+ prev +-----+ +-----+
+ * head | | <---- | | <---- | | tail
+ * +------+ +-----+ +-----+
+ * </pre>
+ *
+ * <p>Insertion into a CLH queue requires only a single atomic
+ * operation on "tail", so there is a simple atomic point of
+ * demarcation from unqueued to queued. Similarly, dequeuing
+ * involves only updating the "head". However, it takes a bit
+ * more work for nodes to determine who their successors are,
+ * in part to deal with possible cancellation due to timeouts
+ * and interrupts.
+ *
+ * <p>The "prev" links (not used in original CLH locks), are mainly
+ * needed to handle cancellation. If a node is cancelled, its
+ * successor is (normally) relinked to a non-cancelled
+ * predecessor. For explanation of similar mechanics in the case
+ * of spin locks, see the papers by Scott and Scherer at
+ * http://www.cs.rochester.edu/u/scott/synchronization/
+ *
+ * <p>We also use "next" links to implement blocking mechanics.
+ * The thread id for each node is kept in its own node, so a
+ * predecessor signals the next node to wake up by traversing
+ * next link to determine which thread it is. Determination of
+ * successor must avoid races with newly queued nodes to set
+ * the "next" fields of their predecessors. This is solved
+ * when necessary by checking backwards from the atomically
+ * updated "tail" when a node's successor appears to be null.
+ * (Or, said differently, the next-links are an optimization
+ * so that we don't usually need a backward scan.)
+ *
+ * <p>Cancellation introduces some conservatism to the basic
+ * algorithms. Since we must poll for cancellation of other
+ * nodes, we can miss noticing whether a cancelled node is
+ * ahead or behind us. This is dealt with by always unparking
+ * successors upon cancellation, allowing them to stabilize on
+ * a new predecessor, unless we can identify an uncancelled
+ * predecessor who will carry this responsibility.
+ *
+ * <p>CLH queues need a dummy header node to get started. But
+ * we don't create them on construction, because it would be wasted
+ * effort if there is never contention. Instead, the node
+ * is constructed and head and tail pointers are set upon first
+ * contention.
+ *
+ * <p>Threads waiting on Conditions use the same nodes, but
+ * use an additional link. Conditions only need to link nodes
+ * in simple (non-concurrent) linked queues because they are
+ * only accessed when exclusively held. Upon await, a node is
+ * inserted into a condition queue. Upon signal, the node is
+ * transferred to the main queue. A special value of status
+ * field is used to mark which queue a node is on.
+ *
+ * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+ * Scherer and Michael Scott, along with members of JSR-166
+ * expert group, for helpful ideas, discussions, and critiques
+ * on the design of this class.
+ */
+ static final class Node {
+ /** Marker to indicate a node is waiting in shared mode */
+ static final Node SHARED = new Node();
+ /** Marker to indicate a node is waiting in exclusive mode */
+ static final Node EXCLUSIVE = null;
+
+ /** waitStatus value to indicate thread has cancelled */
+ static final int CANCELLED = 1;
+ /** waitStatus value to indicate successor's thread needs unparking */
+ static final int SIGNAL = -1;
+ /** waitStatus value to indicate thread is waiting on condition */
+ static final int CONDITION = -2;
+ /**
+ * waitStatus value to indicate the next acquireShared should
+ * unconditionally propagate
+ */
+ static final int PROPAGATE = -3;
+
+ /**
+ * Status field, taking on only the values:
+ * SIGNAL: The successor of this node is (or will soon be)
+ * blocked (via park), so the current node must
+ * unpark its successor when it releases or
+ * cancels. To avoid races, acquire methods must
+ * first indicate they need a signal,
+ * then retry the atomic acquire, and then,
+ * on failure, block.
+ * CANCELLED: This node is cancelled due to timeout or interrupt.
+ * Nodes never leave this state. In particular,
+ * a thread with cancelled node never again blocks.
+ * CONDITION: This node is currently on a condition queue.
+ * It will not be used as a sync queue node
+ * until transferred, at which time the status
+ * will be set to 0. (Use of this value here has
+ * nothing to do with the other uses of the
+ * field, but simplifies mechanics.)
+ * PROPAGATE: A releaseShared should be propagated to other
+ * nodes. This is set (for head node only) in
+ * doReleaseShared to ensure propagation
+ * continues, even if other operations have
+ * since intervened.
+ * 0: None of the above
+ *
+ * The values are arranged numerically to simplify use.
+ * Non-negative values mean that a node doesn't need to
+ * signal. So, most code doesn't need to check for particular
+ * values, just for sign.
+ *
+ * The field is initialized to 0 for normal sync nodes, and
+ * CONDITION for condition nodes. It is modified using CAS
+ * (or when possible, unconditional volatile writes).
+ */
+ volatile int waitStatus;
+
+ /**
+ * Link to predecessor node that current node/thread relies on
+ * for checking waitStatus. Assigned during enqueuing, and nulled
+ * out (for sake of GC) only upon dequeuing. Also, upon
+ * cancellation of a predecessor, we short-circuit while
+ * finding a non-cancelled one, which will always exist
+ * because the head node is never cancelled: A node becomes
+ * head only as a result of successful acquire. A
+ * cancelled thread never succeeds in acquiring, and a thread only
+ * cancels itself, not any other node.
+ */
+ volatile Node prev;
+
+ /**
+ * Link to the successor node that the current node/thread
+ * unparks upon release. Assigned during enqueuing, adjusted
+ * when bypassing cancelled predecessors, and nulled out (for
+ * sake of GC) when dequeued. The enq operation does not
+ * assign next field of a predecessor until after attachment,
+ * so seeing a null next field does not necessarily mean that
+ * node is at end of queue. However, if a next field appears
+ * to be null, we can scan prev's from the tail to
+ * double-check. The next field of cancelled nodes is set to
+ * point to the node itself instead of null, to make life
+ * easier for isOnSyncQueue.
+ */
+ volatile Node next;
+
+ /**
+ * The thread that enqueued this node. Initialized on
+ * construction and nulled out after use.
+ */
+ volatile Thread thread;
+
+ /**
+ * Link to next node waiting on condition, or the special
+ * value SHARED. Because condition queues are accessed only
+ * when holding in exclusive mode, we just need a simple
+ * linked queue to hold nodes while they are waiting on
+ * conditions. They are then transferred to the queue to
+ * re-acquire. And because conditions can only be exclusive,
+ * we save a field by using special value to indicate shared
+ * mode.
+ */
+ Node nextWaiter;
+
+ /**
+ * Returns true if node is waiting in shared mode.
+ */
+ final boolean isShared() {
+ return nextWaiter == SHARED;
+ }
+
+ /**
+ * Returns previous node, or throws NullPointerException if null.
+ * Use when predecessor cannot be null. The null check could
+ * be elided, but is present to help the VM.
+ *
+ * @return the predecessor of this node
+ */
+ final Node predecessor() throws NullPointerException {
+ Node p = prev;
+ if (p == null)
+ throw new NullPointerException();
+ else
+ return p;
+ }
+
+ Node() { // Used to establish initial head or SHARED marker
+ }
+
+ Node(Thread thread, Node mode) { // Used by addWaiter
+ this.nextWaiter = mode;
+ this.thread = thread;
+ }
+
+ Node(Thread thread, int waitStatus) { // Used by Condition
+ this.waitStatus = waitStatus;
+ this.thread = thread;
+ }
+ }
+
+ /**
* Head of the wait queue, lazily initialized. Except for
* initialization, it is modified only via method setHead. Note:
* If head exists, its waitStatus is guaranteed not to be
@@ -82,9 +297,7 @@
* @param newState the new state value
*/
protected final void setState(long newState) {
- // Use putLongVolatile instead of ordinary volatile store when
- // using compareAndSwapLong, for sake of some 32bit systems.
- U.putLongVolatile(this, STATE, newState);
+ state = newState;
}
/**
@@ -95,11 +308,12 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that the actual
+ * @return true if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(long expect, long update) {
- return U.compareAndSwapLong(this, STATE, expect, update);
+ // See below for intrinsics setup to support this
+ return unsafe.compareAndSwapLong(this, stateOffset, expect, update);
}
// Queuing utilities
@@ -109,24 +323,25 @@
* rather than to use timed park. A rough estimate suffices
* to improve responsiveness with very short timeouts.
*/
- static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+ static final long spinForTimeoutThreshold = 1000L;
/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
- private Node enq(Node node) {
+ private Node enq(final Node node) {
for (;;) {
- Node oldTail = tail;
- if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
- if (compareAndSetTail(oldTail, node)) {
- oldTail.next = node;
- return oldTail;
- }
+ Node t = tail;
+ if (t == null) { // Must initialize
+ if (compareAndSetHead(new Node()))
+ tail = head;
} else {
- initializeSyncQueue();
+ node.prev = t;
+ if (compareAndSetTail(t, node)) {
+ t.next = node;
+ return t;
+ }
}
}
}
@@ -138,20 +353,18 @@
* @return the new node
*/
private Node addWaiter(Node mode) {
- Node node = new Node(mode);
-
- for (;;) {
- Node oldTail = tail;
- if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
- if (compareAndSetTail(oldTail, node)) {
- oldTail.next = node;
- return node;
- }
- } else {
- initializeSyncQueue();
+ Node node = new Node(Thread.currentThread(), mode);
+ // Try the fast path of enq; backup to full enq on failure
+ Node pred = tail;
+ if (pred != null) {
+ node.prev = pred;
+ if (compareAndSetTail(pred, node)) {
+ pred.next = node;
+ return node;
}
}
+ enq(node);
+ return node;
}
/**
@@ -180,7 +393,7 @@
*/
int ws = node.waitStatus;
if (ws < 0)
- node.compareAndSetWaitStatus(ws, 0);
+ compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
@@ -191,7 +404,7 @@
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
- for (Node p = tail; p != node && p != null; p = p.prev)
+ for (Node p = tail; p != null && p != node; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
@@ -221,12 +434,12 @@
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
- if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+ if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
- !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+ !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
@@ -248,8 +461,7 @@
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
- * or was recorded (as h.waitStatus either before
- * or after setHead) by a previous operation
+ * or was recorded (as h.waitStatus) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
@@ -261,8 +473,7 @@
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
- if (propagate > 0 || h == null || h.waitStatus < 0 ||
- (h = head) == null || h.waitStatus < 0) {
+ if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
@@ -300,18 +511,18 @@
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
- pred.compareAndSetNext(predNext, null);
+ compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
- (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+ (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
- pred.compareAndSetNext(predNext, next);
+ compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
@@ -352,7 +563,7 @@
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
- pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+ compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
@@ -365,7 +576,7 @@
}
/**
- * Convenience method to park and then check if interrupted.
+ * Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
@@ -392,6 +603,7 @@
* @return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, long arg) {
+ boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
@@ -399,15 +611,16 @@
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -418,21 +631,23 @@
private void doAcquireInterruptibly(long arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -449,28 +664,28 @@
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L) {
- cancelAcquire(node);
+ if (nanosTimeout <= 0L)
return false;
- }
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -480,6 +695,7 @@
*/
private void doAcquireShared(long arg) {
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
@@ -491,6 +707,7 @@
p.next = null; // help GC
if (interrupted)
selfInterrupt();
+ failed = false;
return;
}
}
@@ -498,9 +715,9 @@
parkAndCheckInterrupt())
interrupted = true;
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -511,6 +728,7 @@
private void doAcquireSharedInterruptibly(long arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
@@ -519,6 +737,7 @@
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
+ failed = false;
return;
}
}
@@ -526,9 +745,9 @@
parkAndCheckInterrupt())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -545,6 +764,7 @@
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
@@ -553,23 +773,22 @@
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
+ failed = false;
return true;
}
}
nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L) {
- cancelAcquire(node);
+ if (nanosTimeout <= 0L)
return false;
- }
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -893,7 +1112,7 @@
/**
* Queries whether any threads have ever contended to acquire this
- * synchronizer; that is, if an acquire method has ever blocked.
+ * synchronizer; that is if an acquire method has ever blocked.
*
* <p>In this implementation, this operation returns in
* constant time.
@@ -921,7 +1140,7 @@
}
/**
- * Version of getFirstQueuedThread called when fastpath fails.
+ * Version of getFirstQueuedThread called when fastpath fails
*/
private Thread fullGetFirstQueuedThread() {
/*
@@ -948,11 +1167,13 @@
* guaranteeing termination.
*/
+ Node t = tail;
Thread firstThread = null;
- for (Node p = tail; p != null && p != head; p = p.prev) {
- Thread t = p.thread;
- if (t != null)
- firstThread = t;
+ while (t != null && t != head) {
+ Thread tt = t.thread;
+ if (tt != null)
+ firstThread = tt;
+ t = t.prev;
}
return firstThread;
}
@@ -999,9 +1220,9 @@
*
* <p>An invocation of this method is equivalent to (but may be
* more efficient than):
- * <pre> {@code
- * getFirstQueuedThread() != Thread.currentThread()
- * && hasQueuedThreads()}</pre>
+ * <pre> {@code
+ * getFirstQueuedThread() != Thread.currentThread() &&
+ * hasQueuedThreads()}</pre>
*
* <p>Note that because cancellations due to interrupts and
* timeouts may occur at any time, a {@code true} return does not
@@ -1019,7 +1240,7 @@
* tryAcquire} method for a fair, reentrant, exclusive mode
* synchronizer might look like this:
*
- * <pre> {@code
+ * <pre> {@code
* protected boolean tryAcquire(int arg) {
* if (isHeldExclusively()) {
* // A reentrant acquire; increment hold count
@@ -1055,7 +1276,8 @@
* acquire. The value is only an estimate because the number of
* threads may change dynamically while this method traverses
* internal data structures. This method is designed for use in
- * monitoring system state, not for synchronization control.
+ * monitoring system state, not for synchronization
+ * control.
*
* @return the estimated number of threads waiting to acquire
*/
@@ -1080,7 +1302,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
@@ -1098,7 +1320,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getExclusiveQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (!p.isShared()) {
Thread t = p.thread;
@@ -1118,7 +1340,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getSharedQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (p.isShared()) {
Thread t = p.thread;
@@ -1139,9 +1361,10 @@
* @return a string identifying this synchronizer, as well as its state
*/
public String toString() {
- return super.toString()
- + "[State = " + getState() + ", "
- + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+ long s = getState();
+ String q = hasQueuedThreads() ? "non" : "";
+ return super.toString() +
+ "[State = " + s + ", " + q + "empty queue]";
}
@@ -1175,10 +1398,8 @@
* @return true if present
*/
private boolean findNodeFromTail(Node node) {
- // We check for node first, since it's likely to be at or near tail.
- // tail is known to be non-null, so we could re-order to "save"
- // one null check, but we leave it this way to help the VM.
- for (Node p = tail;;) {
+ Node p = tail;
+ for (;;) {
if (p == node)
return true;
if (p == null)
@@ -1198,7 +1419,7 @@
/*
* If cannot change waitStatus, the node has been cancelled.
*/
- if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
@@ -1209,7 +1430,7 @@
*/
Node p = enq(node);
int ws = p.waitStatus;
- if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+ if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
@@ -1222,7 +1443,7 @@
* @return true if cancelled before the node was signalled
*/
final boolean transferAfterCancelledWait(Node node) {
- if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+ if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
@@ -1244,14 +1465,18 @@
* @return previous sync state
*/
final long fullyRelease(Node node) {
+ boolean failed = true;
try {
long savedState = getState();
- if (release(savedState))
+ if (release(savedState)) {
+ failed = false;
return savedState;
- throw new IllegalMonitorStateException();
- } catch (Throwable t) {
- node.waitStatus = Node.CANCELLED;
- throw t;
+ } else {
+ throw new IllegalMonitorStateException();
+ }
+ } finally {
+ if (failed)
+ node.waitStatus = Node.CANCELLED;
}
}
@@ -1296,8 +1521,8 @@
* given condition associated with this synchronizer. Note that
* because timeouts and interrupts may occur at any time, the
* estimate serves only as an upper bound on the actual number of
- * waiters. This method is designed for use in monitoring system
- * state, not for synchronization control.
+ * waiters. This method is designed for use in monitoring of the
+ * system state, not for synchronization control.
*
* @param condition the condition
* @return the estimated number of waiting threads
@@ -1377,9 +1602,7 @@
unlinkCancelledWaiters();
t = lastWaiter;
}
-
- Node node = new Node(Node.CONDITION);
-
+ Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
@@ -1487,12 +1710,12 @@
/**
* Implements uninterruptible condition wait.
* <ol>
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
* </ol>
*/
public final void awaitUninterruptibly() {
@@ -1546,14 +1769,14 @@
/**
* Implements interruptible condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled or interrupted.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled or interrupted.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
public final void await() throws InterruptedException {
@@ -1578,33 +1801,31 @@
/**
* Implements timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
- // We don't check for nanosTimeout <= 0L here, to allow
- // awaitNanos(0) as a way to "yield the lock".
- final long deadline = System.nanoTime() + nanosTimeout;
long initialNanos = nanosTimeout;
Node node = addConditionWaiter();
long savedState = fullyRelease(node);
+ final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -1617,21 +1838,24 @@
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
long remaining = deadline - System.nanoTime(); // avoid overflow
+ // BEGIN android-note Changed from < to <= http://b/24284239
+ // return (remaining < initialNanos) ? remaining : Long.MIN_VALUE;
return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+ // END android-note
}
/**
* Implements absolute timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
- * <li>If timed out while blocked in step 4, return false, else true.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
public final boolean awaitUntil(Date deadline)
@@ -1644,7 +1868,7 @@
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
- if (System.currentTimeMillis() >= abstime) {
+ if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
@@ -1664,15 +1888,15 @@
/**
* Implements timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
- * <li>If timed out while blocked in step 4, return false, else true.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
public final boolean await(long time, TimeUnit unit)
@@ -1680,11 +1904,9 @@
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
- // We don't check for nanosTimeout <= 0L here, to allow
- // await(0, unit) as a way to "yield the lock".
- final long deadline = System.nanoTime() + nanosTimeout;
Node node = addConditionWaiter();
long savedState = fullyRelease(node);
+ final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
@@ -1692,7 +1914,7 @@
timedout = transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -1721,7 +1943,7 @@
/**
* Queries whether any threads are waiting on this condition.
- * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters(ConditionObject)}.
+ * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters}.
*
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -1740,7 +1962,7 @@
/**
* Returns an estimate of the number of threads waiting on
* this condition.
- * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength(ConditionObject)}.
+ * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength}.
*
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -1760,7 +1982,7 @@
/**
* Returns a collection containing those threads that may be
* waiting on this Condition.
- * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads(ConditionObject)}.
+ * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads}.
*
* @return the collection of threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -1769,7 +1991,7 @@
protected final Collection<Thread> getWaitingThreads() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION) {
Thread t = w.thread;
@@ -1790,22 +2012,27 @@
* are at it, we do the same for other CASable fields (which could
* otherwise be done with atomic field updaters).
*/
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long HEAD;
- private static final long TAIL;
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long stateOffset;
+ private static final long headOffset;
+ private static final long tailOffset;
+ private static final long waitStatusOffset;
+ private static final long nextOffset;
static {
try {
- STATE = U.objectFieldOffset
+ stateOffset = unsafe.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
- HEAD = U.objectFieldOffset
+ headOffset = unsafe.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
+ tailOffset = unsafe.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ waitStatusOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("waitStatus"));
+ nextOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+
+ } catch (Exception ex) { throw new Error(ex); }
// Reduce the risk of rare disastrous classloading in first call to
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
@@ -1813,18 +2040,35 @@
}
/**
- * Initializes head and tail fields on first contention.
+ * CAS head field. Used only by enq.
*/
- private final void initializeSyncQueue() {
- Node h;
- if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
- tail = h;
+ private final boolean compareAndSetHead(Node update) {
+ return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
/**
- * CASes tail field.
+ * CAS tail field. Used only by enq.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
- return U.compareAndSwapObject(this, TAIL, expect, update);
+ return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
+ }
+
+ /**
+ * CAS waitStatus field of a node.
+ */
+ private static final boolean compareAndSetWaitStatus(Node node,
+ int expect,
+ int update) {
+ return unsafe.compareAndSwapInt(node, waitStatusOffset,
+ expect, update);
+ }
+
+ /**
+ * CAS next field of a node.
+ */
+ private static final boolean compareAndSetNext(Node node,
+ Node expect,
+ Node update) {
+ return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 2c41000..8823b6f 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -6,11 +6,15 @@
package java.util.concurrent.locks;
+import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
-import java.util.concurrent.TimeUnit;
-/// OPENJDK-9 import jdk.internal.vm.annotation.ReservedStackAccess;
+import sun.misc.Unsafe;
+
+// BEGIN android-note
+// Use older class level documentation to not @link to hasQueuedPredecessors
+// END android-changed
/**
* Provides a framework for implementing blocking locks and related
@@ -82,11 +86,11 @@
* #setState} and/or {@link #compareAndSetState}:
*
* <ul>
- * <li>{@link #tryAcquire}
- * <li>{@link #tryRelease}
- * <li>{@link #tryAcquireShared}
- * <li>{@link #tryReleaseShared}
- * <li>{@link #isHeldExclusively}
+ * <li> {@link #tryAcquire}
+ * <li> {@link #tryRelease}
+ * <li> {@link #tryAcquireShared}
+ * <li> {@link #tryReleaseShared}
+ * <li> {@link #isHeldExclusively}
* </ul>
*
* Each of these methods by default throws {@link
@@ -127,7 +131,7 @@
* disable barging by internally invoking one or more of the inspection
* methods, thereby providing a <em>fair</em> FIFO acquisition order.
* In particular, most fair synchronizers can define {@code tryAcquire}
- * to return {@code false} if {@link #hasQueuedPredecessors} (a method
+ * to return {@code false} if {@code hasQueuedPredecessors} (a method
* specifically designed to be used by fair synchronizers) returns
* {@code true}. Other variations are possible.
*
@@ -167,7 +171,7 @@
* It also supports conditions and exposes
* one of the instrumentation methods:
*
- * <pre> {@code
+ * <pre> {@code
* class Mutex implements Lock, java.io.Serializable {
*
* // Our internal helper class
@@ -231,7 +235,7 @@
* fire. Because a latch is non-exclusive, it uses the {@code shared}
* acquire and release methods.
*
- * <pre> {@code
+ * <pre> {@code
* class BooleanLatch {
*
* private static class Sync extends AbstractQueuedSynchronizer {
@@ -355,15 +359,15 @@
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
- /** waitStatus value to indicate thread has cancelled. */
+ /** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
- /** waitStatus value to indicate successor's thread needs unparking. */
+ /** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
- /** waitStatus value to indicate thread is waiting on condition. */
+ /** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
- * unconditionally propagate.
+ * unconditionally propagate
*/
static final int PROPAGATE = -3;
@@ -471,49 +475,17 @@
return p;
}
- /** Establishes initial head or SHARED marker. */
- Node() {}
-
- /** Constructor used by addWaiter. */
- Node(Node nextWaiter) {
- this.nextWaiter = nextWaiter;
- U.putObject(this, THREAD, Thread.currentThread());
+ Node() { // Used to establish initial head or SHARED marker
}
- /** Constructor used by addConditionWaiter. */
- Node(int waitStatus) {
- U.putInt(this, WAITSTATUS, waitStatus);
- U.putObject(this, THREAD, Thread.currentThread());
+ Node(Thread thread, Node mode) { // Used by addWaiter
+ this.nextWaiter = mode;
+ this.thread = thread;
}
- /** CASes waitStatus field. */
- final boolean compareAndSetWaitStatus(int expect, int update) {
- return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
- }
-
- /** CASes next field. */
- final boolean compareAndSetNext(Node expect, Node update) {
- return U.compareAndSwapObject(this, NEXT, expect, update);
- }
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long NEXT;
- static final long PREV;
- private static final long THREAD;
- private static final long WAITSTATUS;
- static {
- try {
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- PREV = U.objectFieldOffset
- (Node.class.getDeclaredField("prev"));
- THREAD = U.objectFieldOffset
- (Node.class.getDeclaredField("thread"));
- WAITSTATUS = U.objectFieldOffset
- (Node.class.getDeclaredField("waitStatus"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ Node(Thread thread, int waitStatus) { // Used by Condition
+ this.waitStatus = waitStatus;
+ this.thread = thread;
}
}
@@ -562,11 +534,12 @@
*
* @param expect the expected value
* @param update the new value
- * @return {@code true} if successful. False return indicates that the actual
+ * @return true if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
- return U.compareAndSwapInt(this, STATE, expect, update);
+ // See below for intrinsics setup to support this
+ return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// Queuing utilities
@@ -576,24 +549,25 @@
* rather than to use timed park. A rough estimate suffices
* to improve responsiveness with very short timeouts.
*/
- static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+ static final long spinForTimeoutThreshold = 1000L;
/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
- private Node enq(Node node) {
+ private Node enq(final Node node) {
for (;;) {
- Node oldTail = tail;
- if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
- if (compareAndSetTail(oldTail, node)) {
- oldTail.next = node;
- return oldTail;
- }
+ Node t = tail;
+ if (t == null) { // Must initialize
+ if (compareAndSetHead(new Node()))
+ tail = head;
} else {
- initializeSyncQueue();
+ node.prev = t;
+ if (compareAndSetTail(t, node)) {
+ t.next = node;
+ return t;
+ }
}
}
}
@@ -605,20 +579,18 @@
* @return the new node
*/
private Node addWaiter(Node mode) {
- Node node = new Node(mode);
-
- for (;;) {
- Node oldTail = tail;
- if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
- if (compareAndSetTail(oldTail, node)) {
- oldTail.next = node;
- return node;
- }
- } else {
- initializeSyncQueue();
+ Node node = new Node(Thread.currentThread(), mode);
+ // Try the fast path of enq; backup to full enq on failure
+ Node pred = tail;
+ if (pred != null) {
+ node.prev = pred;
+ if (compareAndSetTail(pred, node)) {
+ pred.next = node;
+ return node;
}
}
+ enq(node);
+ return node;
}
/**
@@ -647,7 +619,7 @@
*/
int ws = node.waitStatus;
if (ws < 0)
- node.compareAndSetWaitStatus(ws, 0);
+ compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
@@ -658,9 +630,9 @@
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
- for (Node p = tail; p != node && p != null; p = p.prev)
- if (p.waitStatus <= 0)
- s = p;
+ for (Node t = tail; t != null && t != node; t = t.prev)
+ if (t.waitStatus <= 0)
+ s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
@@ -688,12 +660,12 @@
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
- if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+ if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
- !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+ !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
@@ -715,8 +687,7 @@
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
- * or was recorded (as h.waitStatus either before
- * or after setHead) by a previous operation
+ * or was recorded (as h.waitStatus) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
@@ -728,8 +699,7 @@
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
- if (propagate > 0 || h == null || h.waitStatus < 0 ||
- (h = head) == null || h.waitStatus < 0) {
+ if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
@@ -767,18 +737,18 @@
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
- pred.compareAndSetNext(predNext, null);
+ compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
- (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+ (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
- pred.compareAndSetNext(predNext, next);
+ compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
@@ -819,7 +789,7 @@
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
- pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+ compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
@@ -832,7 +802,7 @@
}
/**
- * Convenience method to park and then check if interrupted.
+ * Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
@@ -858,8 +828,8 @@
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
-/// OPENJDK-9 @ReservedStackAccess
final boolean acquireQueued(final Node node, int arg) {
+ boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
@@ -867,15 +837,16 @@
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -886,21 +857,23 @@
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -917,28 +890,28 @@
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
+ failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L) {
- cancelAcquire(node);
+ if (nanosTimeout <= 0L)
return false;
- }
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -948,6 +921,7 @@
*/
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
@@ -959,6 +933,7 @@
p.next = null; // help GC
if (interrupted)
selfInterrupt();
+ failed = false;
return;
}
}
@@ -966,9 +941,9 @@
parkAndCheckInterrupt())
interrupted = true;
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -979,6 +954,7 @@
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
@@ -987,6 +963,7 @@
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
+ failed = false;
return;
}
}
@@ -994,9 +971,9 @@
parkAndCheckInterrupt())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -1013,6 +990,7 @@
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.SHARED);
+ boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
@@ -1021,23 +999,22 @@
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
+ failed = false;
return true;
}
}
nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L) {
- cancelAcquire(node);
+ if (nanosTimeout <= 0L)
return false;
- }
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
- } catch (Throwable t) {
- cancelAcquire(node);
- throw t;
+ } finally {
+ if (failed)
+ cancelAcquire(node);
}
}
@@ -1191,7 +1168,6 @@
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
-/// OPENJDK-9 @ReservedStackAccess
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@@ -1255,7 +1231,6 @@
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
-/// OPENJDK-9 @ReservedStackAccess
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
@@ -1336,7 +1311,6 @@
* and can represent anything you like.
* @return the value returned from {@link #tryReleaseShared}
*/
-/// OPENJDK-9 @ReservedStackAccess
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
@@ -1364,7 +1338,7 @@
/**
* Queries whether any threads have ever contended to acquire this
- * synchronizer; that is, if an acquire method has ever blocked.
+ * synchronizer; that is if an acquire method has ever blocked.
*
* <p>In this implementation, this operation returns in
* constant time.
@@ -1392,7 +1366,7 @@
}
/**
- * Version of getFirstQueuedThread called when fastpath fails.
+ * Version of getFirstQueuedThread called when fastpath fails
*/
private Thread fullGetFirstQueuedThread() {
/*
@@ -1419,11 +1393,13 @@
* guaranteeing termination.
*/
+ Node t = tail;
Thread firstThread = null;
- for (Node p = tail; p != null && p != head; p = p.prev) {
- Thread t = p.thread;
- if (t != null)
- firstThread = t;
+ while (t != null && t != head) {
+ Thread tt = t.thread;
+ if (tt != null)
+ firstThread = tt;
+ t = t.prev;
}
return firstThread;
}
@@ -1470,9 +1446,9 @@
*
* <p>An invocation of this method is equivalent to (but may be
* more efficient than):
- * <pre> {@code
- * getFirstQueuedThread() != Thread.currentThread()
- * && hasQueuedThreads()}</pre>
+ * <pre> {@code
+ * getFirstQueuedThread() != Thread.currentThread() &&
+ * hasQueuedThreads()}</pre>
*
* <p>Note that because cancellations due to interrupts and
* timeouts may occur at any time, a {@code true} return does not
@@ -1490,7 +1466,7 @@
* tryAcquire} method for a fair, reentrant, exclusive mode
* synchronizer might look like this:
*
- * <pre> {@code
+ * <pre> {@code
* protected boolean tryAcquire(int arg) {
* if (isHeldExclusively()) {
* // A reentrant acquire; increment hold count
@@ -1526,7 +1502,8 @@
* acquire. The value is only an estimate because the number of
* threads may change dynamically while this method traverses
* internal data structures. This method is designed for use in
- * monitoring system state, not for synchronization control.
+ * monitoring system state, not for synchronization
+ * control.
*
* @return the estimated number of threads waiting to acquire
*/
@@ -1551,7 +1528,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
@@ -1569,7 +1546,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getExclusiveQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (!p.isShared()) {
Thread t = p.thread;
@@ -1589,7 +1566,7 @@
* @return the collection of threads
*/
public final Collection<Thread> getSharedQueuedThreads() {
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (p.isShared()) {
Thread t = p.thread;
@@ -1610,9 +1587,10 @@
* @return a string identifying this synchronizer, as well as its state
*/
public String toString() {
- return super.toString()
- + "[State = " + getState() + ", "
- + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+ int s = getState();
+ String q = hasQueuedThreads() ? "non" : "";
+ return super.toString() +
+ "[State = " + s + ", " + q + "empty queue]";
}
@@ -1646,15 +1624,13 @@
* @return true if present
*/
private boolean findNodeFromTail(Node node) {
- // We check for node first, since it's likely to be at or near tail.
- // tail is known to be non-null, so we could re-order to "save"
- // one null check, but we leave it this way to help the VM.
- for (Node p = tail;;) {
- if (p == node)
+ Node t = tail;
+ for (;;) {
+ if (t == node)
return true;
- if (p == null)
+ if (t == null)
return false;
- p = p.prev;
+ t = t.prev;
}
}
@@ -1669,7 +1645,7 @@
/*
* If cannot change waitStatus, the node has been cancelled.
*/
- if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
@@ -1680,7 +1656,7 @@
*/
Node p = enq(node);
int ws = p.waitStatus;
- if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+ if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
@@ -1693,7 +1669,7 @@
* @return true if cancelled before the node was signalled
*/
final boolean transferAfterCancelledWait(Node node) {
- if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+ if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
@@ -1715,14 +1691,18 @@
* @return previous sync state
*/
final int fullyRelease(Node node) {
+ boolean failed = true;
try {
int savedState = getState();
- if (release(savedState))
+ if (release(savedState)) {
+ failed = false;
return savedState;
- throw new IllegalMonitorStateException();
- } catch (Throwable t) {
- node.waitStatus = Node.CANCELLED;
- throw t;
+ } else {
+ throw new IllegalMonitorStateException();
+ }
+ } finally {
+ if (failed)
+ node.waitStatus = Node.CANCELLED;
}
}
@@ -1767,8 +1747,8 @@
* given condition associated with this synchronizer. Note that
* because timeouts and interrupts may occur at any time, the
* estimate serves only as an upper bound on the actual number of
- * waiters. This method is designed for use in monitoring system
- * state, not for synchronization control.
+ * waiters. This method is designed for use in monitoring of the
+ * system state, not for synchronization control.
*
* @param condition the condition
* @return the estimated number of waiting threads
@@ -1846,9 +1826,7 @@
unlinkCancelledWaiters();
t = lastWaiter;
}
-
- Node node = new Node(Node.CONDITION);
-
+ Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
@@ -1956,12 +1934,12 @@
/**
* Implements uninterruptible condition wait.
* <ol>
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
* </ol>
*/
public final void awaitUninterruptibly() {
@@ -2015,14 +1993,14 @@
/**
* Implements interruptible condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled or interrupted.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled or interrupted.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
public final void await() throws InterruptedException {
@@ -2047,33 +2025,31 @@
/**
* Implements timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
- // We don't check for nanosTimeout <= 0L here, to allow
- // awaitNanos(0) as a way to "yield the lock".
- final long deadline = System.nanoTime() + nanosTimeout;
long initialNanos = nanosTimeout;
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
+ final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -2086,21 +2062,24 @@
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
long remaining = deadline - System.nanoTime(); // avoid overflow
+ // BEGIN android-note Changed from < to <= http://b/24284239
+ // return (remaining < initialNanos) ? remaining : Long.MIN_VALUE;
return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+ // END android-note
}
/**
* Implements absolute timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
- * <li>If timed out while blocked in step 4, return false, else true.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
public final boolean awaitUntil(Date deadline)
@@ -2113,7 +2092,7 @@
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
- if (System.currentTimeMillis() >= abstime) {
+ if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
@@ -2133,15 +2112,15 @@
/**
* Implements timed condition wait.
* <ol>
- * <li>If current thread is interrupted, throw InterruptedException.
- * <li>Save lock state returned by {@link #getState}.
- * <li>Invoke {@link #release} with saved state as argument,
- * throwing IllegalMonitorStateException if it fails.
- * <li>Block until signalled, interrupted, or timed out.
- * <li>Reacquire by invoking specialized version of
- * {@link #acquire} with saved state as argument.
- * <li>If interrupted while blocked in step 4, throw InterruptedException.
- * <li>If timed out while blocked in step 4, return false, else true.
+ * <li> If current thread is interrupted, throw InterruptedException.
+ * <li> Save lock state returned by {@link #getState}.
+ * <li> Invoke {@link #release} with saved state as argument,
+ * throwing IllegalMonitorStateException if it fails.
+ * <li> Block until signalled, interrupted, or timed out.
+ * <li> Reacquire by invoking specialized version of
+ * {@link #acquire} with saved state as argument.
+ * <li> If interrupted while blocked in step 4, throw InterruptedException.
+ * <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
public final boolean await(long time, TimeUnit unit)
@@ -2149,11 +2128,9 @@
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
- // We don't check for nanosTimeout <= 0L here, to allow
- // await(0, unit) as a way to "yield the lock".
- final long deadline = System.nanoTime() + nanosTimeout;
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
+ final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
@@ -2161,7 +2138,7 @@
timedout = transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+ if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -2190,7 +2167,7 @@
/**
* Queries whether any threads are waiting on this condition.
- * Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
+ * Implements {@link AbstractQueuedSynchronizer#hasWaiters}.
*
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -2209,7 +2186,7 @@
/**
* Returns an estimate of the number of threads waiting on
* this condition.
- * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
+ * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength}.
*
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -2229,7 +2206,7 @@
/**
* Returns a collection containing those threads that may be
* waiting on this Condition.
- * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
+ * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads}.
*
* @return the collection of threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -2238,7 +2215,7 @@
protected final Collection<Thread> getWaitingThreads() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
- ArrayList<Thread> list = new ArrayList<>();
+ ArrayList<Thread> list = new ArrayList<Thread>();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION) {
Thread t = w.thread;
@@ -2259,22 +2236,27 @@
* are at it, we do the same for other CASable fields (which could
* otherwise be done with atomic field updaters).
*/
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long HEAD;
- private static final long TAIL;
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long stateOffset;
+ private static final long headOffset;
+ private static final long tailOffset;
+ private static final long waitStatusOffset;
+ private static final long nextOffset;
static {
try {
- STATE = U.objectFieldOffset
+ stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
- HEAD = U.objectFieldOffset
+ headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
+ tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ waitStatusOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("waitStatus"));
+ nextOffset = unsafe.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+
+ } catch (Exception ex) { throw new Error(ex); }
// Reduce the risk of rare disastrous classloading in first call to
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
@@ -2282,18 +2264,35 @@
}
/**
- * Initializes head and tail fields on first contention.
+ * CAS head field. Used only by enq.
*/
- private final void initializeSyncQueue() {
- Node h;
- if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
- tail = h;
+ private final boolean compareAndSetHead(Node update) {
+ return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
/**
- * CASes tail field.
+ * CAS tail field. Used only by enq.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
- return U.compareAndSwapObject(this, TAIL, expect, update);
+ return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
+ }
+
+ /**
+ * CAS waitStatus field of a node.
+ */
+ private static final boolean compareAndSetWaitStatus(Node node,
+ int expect,
+ int update) {
+ return unsafe.compareAndSwapInt(node, waitStatusOffset,
+ expect, update);
+ }
+
+ /**
+ * CAS next field of a node.
+ */
+ private static final boolean compareAndSetNext(Node node,
+ Node expect,
+ Node update) {
+ return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
}
diff --git a/luni/src/main/java/java/util/concurrent/locks/Condition.java b/luni/src/main/java/java/util/concurrent/locks/Condition.java
index b3132e7..11a7090 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Condition.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Condition.java
@@ -6,8 +6,8 @@
package java.util.concurrent.locks;
-import java.util.Date;
import java.util.concurrent.TimeUnit;
+import java.util.Date;
/**
* {@code Condition} factors out the {@code Object} monitor
@@ -98,7 +98,7 @@
* <p>Note that {@code Condition} instances are just normal objects and can
* themselves be used as the target in a {@code synchronized} statement,
* and can have their own monitor {@link Object#wait wait} and
- * {@link Object#notify notify} methods invoked.
+ * {@link Object#notify notification} methods invoked.
* Acquiring the monitor lock of a {@code Condition} instance, or using its
* monitor methods, has no specified relationship with acquiring the
* {@link Lock} associated with that {@code Condition} or the use of its
@@ -280,7 +280,7 @@
* condition still does not hold. Typical uses of this method take
* the following form:
*
- * <pre> {@code
+ * <pre> {@code
* boolean aMethod(long timeout, TimeUnit unit) {
* long nanos = unit.toNanos(timeout);
* lock.lock();
@@ -333,7 +333,7 @@
* Causes the current thread to wait until it is signalled or interrupted,
* or the specified waiting time elapses. This method is behaviorally
* equivalent to:
- * <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
+ * <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
*
* @param time the maximum time to wait
* @param unit the time unit of the {@code time} argument
@@ -382,7 +382,7 @@
*
* <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows:
- * <pre> {@code
+ * <pre> {@code
* boolean aMethod(Date deadline) {
* boolean stillWaiting = true;
* lock.lock();
diff --git a/luni/src/main/java/java/util/concurrent/locks/Lock.java b/luni/src/main/java/java/util/concurrent/locks/Lock.java
index a2d7b48..a7ca001 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Lock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Lock.java
@@ -49,7 +49,7 @@
* methods and statements. In most cases, the following idiom
* should be used:
*
- * <pre> {@code
+ * <pre> {@code
* Lock l = ...;
* l.lock();
* try {
@@ -93,9 +93,8 @@
* <p>All {@code Lock} implementations <em>must</em> enforce the same
* memory synchronization semantics as provided by the built-in monitor
* lock, as described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
- * Chapter 17 of
- * <cite>The Java™ Language Specification</cite></a>:
+ * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4">
+ * The Java Language Specification (17.4 Memory Model)</a>:
* <ul>
* <li>A successful {@code lock} operation has the same memory
* synchronization effects as a successful <em>Lock</em> action.
@@ -213,7 +212,7 @@
* immediately with the value {@code false}.
*
* <p>A typical usage idiom for this method would be:
- * <pre> {@code
+ * <pre> {@code
* Lock lock = ...;
* if (lock.tryLock()) {
* try {
diff --git a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
index 694f4ca..089d818 100644
--- a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
+++ b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
@@ -6,6 +6,8 @@
package java.util.concurrent.locks;
+import sun.misc.Unsafe;
+
/**
* Basic thread blocking primitives for creating locks and other
* synchronization classes.
@@ -17,10 +19,6 @@
* it <em>may</em> block. A call to {@code unpark} makes the permit
* available, if it was not already available. (Unlike with Semaphores
* though, permits do not accumulate. There is at most one.)
- * Reliable usage requires the use of volatile (or atomic) variables
- * to control when to park or unpark. Orderings of calls to these
- * methods are maintained with respect to volatile variable accesses,
- * but not necessarily non-volatile variable accesses.
*
* <p>Methods {@code park} and {@code unpark} provide efficient
* means of blocking and unblocking threads that do not encounter the
@@ -41,74 +39,73 @@
* {@code blocker} object parameter. This object is recorded while
* the thread is blocked to permit monitoring and diagnostic tools to
* identify the reasons that threads are blocked. (Such tools may
- * access blockers using method {@link #getBlocker(Thread)}.)
- * The use of these forms rather than the original forms without this
- * parameter is strongly encouraged. The normal argument to supply as
- * a {@code blocker} within a lock implementation is {@code this}.
+ * access blockers using method {@link #getBlocker}.) The use of these
+ * forms rather than the original forms without this parameter is
+ * strongly encouraged. The normal argument to supply as a
+ * {@code blocker} within a lock implementation is {@code this}.
*
* <p>These methods are designed to be used as tools for creating
* higher-level synchronization utilities, and are not in themselves
* useful for most concurrency control applications. The {@code park}
* method is designed for use only in constructions of the form:
*
- * <pre> {@code
- * while (!canProceed()) {
- * // ensure request to unpark is visible to other threads
- * ...
- * LockSupport.park(this);
- * }}</pre>
+ * <pre> {@code
+ * while (!canProceed()) { ... LockSupport.park(this); }}</pre>
*
- * where no actions by the thread publishing a request to unpark,
- * prior to the call to {@code park}, entail locking or blocking.
- * Because only one permit is associated with each thread, any
- * intermediary uses of {@code park}, including implicitly via class
- * loading, could lead to an unresponsive thread (a "lost unpark").
+ * where neither {@code canProceed} nor any other actions prior to the
+ * call to {@code park} entail locking or blocking. Because only one
+ * permit is associated with each thread, any intermediary uses of
+ * {@code park} could interfere with its intended effects.
*
* <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
* non-reentrant lock class:
- * <pre> {@code
+ * <pre> {@code
* class FIFOMutex {
* private final AtomicBoolean locked = new AtomicBoolean(false);
* private final Queue<Thread> waiters
- * = new ConcurrentLinkedQueue<>();
+ * = new ConcurrentLinkedQueue<Thread>();
*
* public void lock() {
* boolean wasInterrupted = false;
- * // publish current thread for unparkers
- * waiters.add(Thread.currentThread());
+ * Thread current = Thread.currentThread();
+ * waiters.add(current);
*
* // Block while not first in queue or cannot acquire lock
- * while (waiters.peek() != Thread.currentThread() ||
+ * while (waiters.peek() != current ||
* !locked.compareAndSet(false, true)) {
* LockSupport.park(this);
- * // ignore interrupts while waiting
- * if (Thread.interrupted())
+ * if (Thread.interrupted()) // ignore interrupts while waiting
* wasInterrupted = true;
* }
*
* waiters.remove();
- * // ensure correct interrupt status on return
- * if (wasInterrupted)
- * Thread.currentThread().interrupt();
+ * if (wasInterrupted) // reassert interrupt status on exit
+ * current.interrupt();
* }
*
* public void unlock() {
* locked.set(false);
* LockSupport.unpark(waiters.peek());
* }
- *
- * static {
- * // Reduce the risk of "lost unpark" due to classloading
- * Class<?> ensureLoaded = LockSupport.class;
- * }
* }}</pre>
*/
public class LockSupport {
private LockSupport() {} // Cannot be instantiated.
+ // Hotspot implementation via intrinsics API
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final long parkBlockerOffset;
+
+ static {
+ try {
+ parkBlockerOffset = unsafe.objectFieldOffset
+ (java.lang.Thread.class.getDeclaredField("parkBlocker"));
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
- U.putObject(t, PARKBLOCKER, arg);
+ unsafe.putObject(t, parkBlockerOffset, arg);
}
/**
@@ -124,7 +121,7 @@
*/
public static void unpark(Thread thread) {
if (thread != null)
- U.unpark(thread);
+ unsafe.unpark(thread);
}
/**
@@ -158,7 +155,7 @@
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
- U.park(false, 0L);
+ unsafe.park(false, 0L);
setBlocker(t, null);
}
@@ -198,7 +195,7 @@
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
- U.park(false, nanos);
+ unsafe.park(false, nanos);
setBlocker(t, null);
}
}
@@ -239,7 +236,7 @@
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
- U.park(true, deadline);
+ unsafe.park(true, deadline);
setBlocker(t, null);
}
@@ -258,7 +255,7 @@
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
- return U.getObjectVolatile(t, PARKBLOCKER);
+ return unsafe.getObjectVolatile(t, parkBlockerOffset);
}
/**
@@ -287,7 +284,7 @@
* for example, the interrupt status of the thread upon return.
*/
public static void park() {
- U.park(false, 0L);
+ unsafe.park(false, 0L);
}
/**
@@ -321,7 +318,7 @@
*/
public static void parkNanos(long nanos) {
if (nanos > 0)
- U.park(false, nanos);
+ unsafe.park(false, nanos);
}
/**
@@ -355,40 +352,6 @@
* to wait until
*/
public static void parkUntil(long deadline) {
- U.park(true, deadline);
+ unsafe.park(true, deadline);
}
-
- /**
- * Returns the pseudo-randomly initialized or updated secondary seed.
- * Copied from ThreadLocalRandom due to package access restrictions.
- */
- static final int nextSecondarySeed() {
- int r;
- Thread t = Thread.currentThread();
- if ((r = U.getInt(t, SECONDARY)) != 0) {
- r ^= r << 13; // xorshift
- r ^= r >>> 17;
- r ^= r << 5;
- }
- else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
- r = 1; // avoid zero
- U.putInt(t, SECONDARY, r);
- return r;
- }
-
- // Hotspot implementation via intrinsics API
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PARKBLOCKER;
- private static final long SECONDARY;
- static {
- try {
- PARKBLOCKER = U.objectFieldOffset
- (Thread.class.getDeclaredField("parkBlocker"));
- SECONDARY = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
}
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
index a1a211a..8690355 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
@@ -9,9 +9,9 @@
/**
* A {@code ReadWriteLock} maintains a pair of associated {@link
* Lock locks}, one for read-only operations and one for writing.
- * The {@linkplain #readLock read lock} may be held simultaneously
- * by multiple reader threads, so long as there are no writers.
- * The {@linkplain #writeLock write lock} is exclusive.
+ * The {@link #readLock read lock} may be held simultaneously by
+ * multiple reader threads, so long as there are no writers. The
+ * {@link #writeLock write lock} is exclusive.
*
* <p>All {@code ReadWriteLock} implementations must guarantee that
* the memory synchronization effects of {@code writeLock} operations
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
index 5fedcaa..3654248 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
@@ -6,9 +6,8 @@
package java.util.concurrent.locks;
-import java.util.Collection;
import java.util.concurrent.TimeUnit;
-/// OPENJDK-9 import jdk.internal.vm.annotation.ReservedStackAccess;
+import java.util.Collection;
/**
* A reentrant mutual exclusion {@link Lock} with the same basic
@@ -45,7 +44,7 @@
* follow a call to {@code lock} with a {@code try} block, most
* typically in a before/after construction such as:
*
- * <pre> {@code
+ * <pre> {@code
* class X {
* private final ReentrantLock lock = new ReentrantLock();
* // ...
@@ -99,7 +98,6 @@
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
-/// OPENJDK-9 @ReservedStackAccess
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
@@ -119,7 +117,6 @@
return false;
}
-/// OPENJDK-9 @ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
@@ -177,7 +174,6 @@
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
-/// OPENJDK-9 @ReservedStackAccess
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
@@ -204,7 +200,6 @@
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
-/// OPENJDK-9 @ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
@@ -355,7 +350,7 @@
* method. If you want a timed {@code tryLock} that does permit barging on
* a fair lock then combine the timed and un-timed forms together:
*
- * <pre> {@code
+ * <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
@@ -461,7 +456,7 @@
* InterruptedException} will be thrown, and the thread's
* interrupted status will be cleared.
*
- * <li>Waiting threads are signalled in FIFO order.
+ * <li> Waiting threads are signalled in FIFO order.
*
* <li>The ordering of lock reacquisition for threads returning
* from waiting methods is the same as for threads initially
@@ -488,7 +483,7 @@
* not be entered with the lock already held then we can assert that
* fact:
*
- * <pre> {@code
+ * <pre> {@code
* class X {
* ReentrantLock lock = new ReentrantLock();
* // ...
@@ -513,12 +508,12 @@
/**
* Queries if this lock is held by the current thread.
*
- * <p>Analogous to the {@link Thread#holdsLock(Object)} method for
- * built-in monitor locks, this method is typically used for
- * debugging and testing. For example, a method that should only be
- * called while a lock is held can assert that this is the case:
+ * <p>Analogous to the {@link Thread#holdsLock} method for built-in
+ * monitor locks, this method is typically used for debugging and
+ * testing. For example, a method that should only be called while
+ * a lock is held can assert that this is the case:
*
- * <pre> {@code
+ * <pre> {@code
* class X {
* ReentrantLock lock = new ReentrantLock();
* // ...
@@ -532,7 +527,7 @@
* <p>It can also be used to ensure that a reentrant lock is used
* in a non-reentrant manner, for example:
*
- * <pre> {@code
+ * <pre> {@code
* class X {
* ReentrantLock lock = new ReentrantLock();
* // ...
@@ -623,11 +618,12 @@
}
/**
- * Returns an estimate of the number of threads waiting to acquire
- * this lock. The value is only an estimate because the number of
+ * Returns an estimate of the number of threads waiting to
+ * acquire this lock. The value is only an estimate because the number of
* threads may change dynamically while this method traverses
* internal data structures. This method is designed for use in
- * monitoring system state, not for synchronization control.
+ * monitoring of the system state, not for synchronization
+ * control.
*
* @return the estimated number of threads waiting for this lock
*/
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index 8969a54..cc7ba4c 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -6,8 +6,8 @@
package java.util.concurrent.locks;
-import java.util.Collection;
import java.util.concurrent.TimeUnit;
+import java.util.Collection;
/**
* An implementation of {@link ReadWriteLock} supporting similar
@@ -23,16 +23,15 @@
*
* <dl>
* <dt><b><i>Non-fair mode (default)</i></b>
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * When constructed as non-fair (the default), the order of entry
+ * <dd>When constructed as non-fair (the default), the order of entry
* to the read and write lock is unspecified, subject to reentrancy
* constraints. A nonfair lock that is continuously contended may
* indefinitely postpone one or more reader or writer threads, but
* will normally have higher throughput than a fair lock.
+ * <p>
*
* <dt><b><i>Fair mode</i></b>
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * When constructed as fair, threads contend for entry using an
+ * <dd>When constructed as fair, threads contend for entry using an
* approximately arrival-order policy. When the currently held lock
* is released, either the longest-waiting single writer thread will
* be assigned the write lock, or if there is a group of reader threads
@@ -54,6 +53,7 @@
* {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods
* do not honor this fair setting and will immediately acquire the lock
* if it is possible, regardless of waiting threads.)
+ * <p>
* </dl>
*
* <li><b>Reentrancy</b>
@@ -147,9 +147,9 @@
* is a class using a TreeMap that is expected to be large and
* concurrently accessed.
*
- * <pre> {@code
+ * <pre> {@code
* class RWDictionary {
- * private final Map<String, Data> m = new TreeMap<>();
+ * private final Map<String, Data> m = new TreeMap<String, Data>();
* private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
* private final Lock r = rwl.readLock();
* private final Lock w = rwl.writeLock();
@@ -159,9 +159,9 @@
* try { return m.get(key); }
* finally { r.unlock(); }
* }
- * public List<String> allKeys() {
+ * public String[] allKeys() {
* r.lock();
- * try { return new ArrayList<>(m.keySet()); }
+ * try { return m.keySet().toArray(); }
* finally { r.unlock(); }
* }
* public Data put(String key, Data value) {
@@ -247,9 +247,9 @@
* Maintained as a ThreadLocal; cached in cachedHoldCounter.
*/
static final class HoldCounter {
- int count; // initially 0
+ int count = 0;
// Use id, not reference, to avoid garbage retention
- final long tid = getThreadId(Thread.currentThread());
+ final long tid = Thread.currentThread().getId();
}
/**
@@ -392,7 +392,7 @@
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
@@ -450,7 +450,7 @@
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -487,7 +487,7 @@
} else {
if (rh == null) {
rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current)) {
+ if (rh == null || rh.tid != current.getId()) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
@@ -508,7 +508,7 @@
} else {
if (rh == null)
rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -564,7 +564,7 @@
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -615,7 +615,7 @@
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
- if (rh != null && rh.tid == getThreadId(current))
+ if (rh != null && rh.tid == current.getId())
return rh.count;
int count = readHolds.get().count;
@@ -677,7 +677,7 @@
private final Sync sync;
/**
- * Constructor for use by subclasses.
+ * Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
@@ -788,7 +788,7 @@
* permit barging on a fair lock then combine the timed and
* un-timed forms together:
*
- * <pre> {@code
+ * <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
@@ -848,12 +848,7 @@
* Attempts to release this lock.
*
* <p>If the number of readers is now zero then the lock
- * is made available for write lock attempts. If the current
- * thread does not hold this lock then {@link
- * IllegalMonitorStateException} is thrown.
- *
- * @throws IllegalMonitorStateException if the current thread
- * does not hold this lock
+ * is made available for write lock attempts.
*/
public void unlock() {
sync.releaseShared(1);
@@ -891,7 +886,7 @@
private final Sync sync;
/**
- * Constructor for use by subclasses.
+ * Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
@@ -1005,7 +1000,7 @@
* by the current thread, or the write lock was already held
* by the current thread; and {@code false} otherwise.
*/
- public boolean tryLock() {
+ public boolean tryLock( ) {
return sync.tryWriteLock();
}
@@ -1025,7 +1020,7 @@
* that does permit barging on a fair lock then combine the
* timed and un-timed forms together:
*
- * <pre> {@code
+ * <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
@@ -1140,7 +1135,7 @@
* InterruptedException} will be thrown, and the thread's
* interrupted status will be cleared.
*
- * <li>Waiting threads are signalled in FIFO order.
+ * <li> Waiting threads are signalled in FIFO order.
*
* <li>The ordering of lock reacquisition for threads returning
* from waiting methods is the same as for threads initially
@@ -1348,7 +1343,7 @@
* either the read or write lock. The value is only an estimate
* because the number of threads may change dynamically while this
* method traverses internal data structures. This method is
- * designed for use in monitoring system state, not for
+ * designed for use in monitoring of the system state, not for
* synchronization control.
*
* @return the estimated number of threads waiting for this lock
@@ -1461,26 +1456,4 @@
"[Write locks = " + w + ", Read locks = " + r + "]";
}
- /**
- * Returns the thread id for the given thread. We must access
- * this directly rather than via method Thread.getId() because
- * getId() is not final, and has been known to be overridden in
- * ways that do not preserve unique mappings.
- */
- static final long getThreadId(Thread thread) {
- return U.getLongVolatile(thread, TID);
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long TID;
- static {
- try {
- TID = U.objectFieldOffset
- (Thread.class.getDeclaredField("tid"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
}
diff --git a/luni/src/main/java/java/util/concurrent/locks/StampedLock.java b/luni/src/main/java/java/util/concurrent/locks/StampedLock.java
deleted file mode 100644
index 1f4d54f..0000000
--- a/luni/src/main/java/java/util/concurrent/locks/StampedLock.java
+++ /dev/null
@@ -1,1403 +0,0 @@
-/*
- * 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.locks;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A capability-based lock with three modes for controlling read/write
- * access. The state of a StampedLock consists of a version and mode.
- * Lock acquisition methods return a stamp that represents and
- * controls access with respect to a lock state; "try" versions of
- * these methods may instead return the special value zero to
- * represent failure to acquire access. Lock release and conversion
- * methods require stamps as arguments, and fail if they do not match
- * the state of the lock. The three modes are:
- *
- * <ul>
- *
- * <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
- * waiting for exclusive access, returning a stamp that can be used
- * in method {@link #unlockWrite} to release the lock. Untimed and
- * timed versions of {@code tryWriteLock} are also provided. When
- * the lock is held in write mode, no read locks may be obtained,
- * and all optimistic read validations will fail.
- *
- * <li><b>Reading.</b> Method {@link #readLock} possibly blocks
- * waiting for non-exclusive access, returning a stamp that can be
- * used in method {@link #unlockRead} to release the lock. Untimed
- * and timed versions of {@code tryReadLock} are also provided.
- *
- * <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
- * returns a non-zero stamp only if the lock is not currently held
- * in write mode. Method {@link #validate} returns true if the lock
- * has not been acquired in write mode since obtaining a given
- * stamp. This mode can be thought of as an extremely weak version
- * of a read-lock, that can be broken by a writer at any time. The
- * use of optimistic mode for short read-only code segments often
- * reduces contention and improves throughput. However, its use is
- * inherently fragile. Optimistic read sections should only read
- * fields and hold them in local variables for later use after
- * validation. Fields read while in optimistic mode may be wildly
- * inconsistent, so usage applies only when you are familiar enough
- * with data representations to check consistency and/or repeatedly
- * invoke method {@code validate()}. For example, such steps are
- * typically required when first reading an object or array
- * reference, and then accessing one of its fields, elements or
- * methods.
- *
- * </ul>
- *
- * <p>This class also supports methods that conditionally provide
- * conversions across the three modes. For example, method {@link
- * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
- * a valid write stamp if (1) already in writing mode (2) in reading
- * mode and there are no other readers or (3) in optimistic mode and
- * the lock is available. The forms of these methods are designed to
- * help reduce some of the code bloat that otherwise occurs in
- * retry-based designs.
- *
- * <p>StampedLocks are designed for use as internal utilities in the
- * development of thread-safe components. Their use relies on
- * knowledge of the internal properties of the data, objects, and
- * methods they are protecting. They are not reentrant, so locked
- * bodies should not call other unknown methods that may try to
- * re-acquire locks (although you may pass a stamp to other methods
- * that can use or convert it). The use of read lock modes relies on
- * the associated code sections being side-effect-free. Unvalidated
- * optimistic read sections cannot call methods that are not known to
- * tolerate potential inconsistencies. Stamps use finite
- * representations, and are not cryptographically secure (i.e., a
- * valid stamp may be guessable). Stamp values may recycle after (no
- * sooner than) one year of continuous operation. A stamp held without
- * use or validation for longer than this period may fail to validate
- * correctly. StampedLocks are serializable, but always deserialize
- * into initial unlocked state, so they are not useful for remote
- * locking.
- *
- * <p>The scheduling policy of StampedLock does not consistently
- * prefer readers over writers or vice versa. All "try" methods are
- * best-effort and do not necessarily conform to any scheduling or
- * fairness policy. A zero return from any "try" method for acquiring
- * or converting locks does not carry any information about the state
- * of the lock; a subsequent invocation may succeed.
- *
- * <p>Because it supports coordinated usage across multiple lock
- * modes, this class does not directly implement the {@link Lock} or
- * {@link ReadWriteLock} interfaces. However, a StampedLock may be
- * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link
- * #asReadWriteLock()} in applications requiring only the associated
- * set of functionality.
- *
- * <p><b>Sample Usage.</b> The following illustrates some usage idioms
- * in a class that maintains simple two-dimensional points. The sample
- * code illustrates some try/catch conventions even though they are
- * not strictly needed here because no exceptions can occur in their
- * bodies.<br>
- *
- * <pre> {@code
- * class Point {
- * private double x, y;
- * private final StampedLock sl = new StampedLock();
- *
- * void move(double deltaX, double deltaY) { // an exclusively locked method
- * long stamp = sl.writeLock();
- * try {
- * x += deltaX;
- * y += deltaY;
- * } finally {
- * sl.unlockWrite(stamp);
- * }
- * }
- *
- * double distanceFromOrigin() { // A read-only method
- * long stamp = sl.tryOptimisticRead();
- * double currentX = x, currentY = y;
- * if (!sl.validate(stamp)) {
- * stamp = sl.readLock();
- * try {
- * currentX = x;
- * currentY = y;
- * } finally {
- * sl.unlockRead(stamp);
- * }
- * }
- * return Math.sqrt(currentX * currentX + currentY * currentY);
- * }
- *
- * void moveIfAtOrigin(double newX, double newY) { // upgrade
- * // Could instead start with optimistic, not read mode
- * long stamp = sl.readLock();
- * try {
- * while (x == 0.0 && y == 0.0) {
- * long ws = sl.tryConvertToWriteLock(stamp);
- * if (ws != 0L) {
- * stamp = ws;
- * x = newX;
- * y = newY;
- * break;
- * }
- * else {
- * sl.unlockRead(stamp);
- * stamp = sl.writeLock();
- * }
- * }
- * } finally {
- * sl.unlock(stamp);
- * }
- * }
- * }}</pre>
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class StampedLock implements java.io.Serializable {
- /*
- * Algorithmic notes:
- *
- * The design employs elements of Sequence locks
- * (as used in linux kernels; see Lameter's
- * http://www.lameter.com/gelato2005.pdf
- * and elsewhere; see
- * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
- * and Ordered RW locks (see Shirako et al
- * http://dl.acm.org/citation.cfm?id=2312015)
- *
- * Conceptually, the primary state of the lock includes a sequence
- * number that is odd when write-locked and even otherwise.
- * However, this is offset by a reader count that is non-zero when
- * read-locked. The read count is ignored when validating
- * "optimistic" seqlock-reader-style stamps. Because we must use
- * a small finite number of bits (currently 7) for readers, a
- * supplementary reader overflow word is used when the number of
- * readers exceeds the count field. We do this by treating the max
- * reader count value (RBITS) as a spinlock protecting overflow
- * updates.
- *
- * Waiters use a modified form of CLH lock used in
- * AbstractQueuedSynchronizer (see its internal documentation for
- * a fuller account), where each node is tagged (field mode) as
- * either a reader or writer. Sets of waiting readers are grouped
- * (linked) under a common node (field cowait) so act as a single
- * node with respect to most CLH mechanics. By virtue of the
- * queue structure, wait nodes need not actually carry sequence
- * numbers; we know each is greater than its predecessor. This
- * simplifies the scheduling policy to a mainly-FIFO scheme that
- * incorporates elements of Phase-Fair locks (see Brandenburg &
- * Anderson, especially http://www.cs.unc.edu/~bbb/diss/). In
- * particular, we use the phase-fair anti-barging rule: If an
- * incoming reader arrives while read lock is held but there is a
- * queued writer, this incoming reader is queued. (This rule is
- * responsible for some of the complexity of method acquireRead,
- * but without it, the lock becomes highly unfair.) Method release
- * does not (and sometimes cannot) itself wake up cowaiters. This
- * is done by the primary thread, but helped by any other threads
- * with nothing better to do in methods acquireRead and
- * acquireWrite.
- *
- * These rules apply to threads actually queued. All tryLock forms
- * opportunistically try to acquire locks regardless of preference
- * rules, and so may "barge" their way in. Randomized spinning is
- * used in the acquire methods to reduce (increasingly expensive)
- * context switching while also avoiding sustained memory
- * thrashing among many threads. We limit spins to the head of
- * queue. A thread spin-waits up to SPINS times (where each
- * iteration decreases spin count with 50% probability) before
- * blocking. If, upon wakening it fails to obtain lock, and is
- * still (or becomes) the first waiting thread (which indicates
- * that some other thread barged and obtained lock), it escalates
- * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
- * continually losing to barging threads.
- *
- * Nearly all of these mechanics are carried out in methods
- * acquireWrite and acquireRead, that, as typical of such code,
- * sprawl out because actions and retries rely on consistent sets
- * of locally cached reads.
- *
- * As noted in Boehm's paper (above), sequence validation (mainly
- * method validate()) requires stricter ordering rules than apply
- * to normal volatile reads (of "state"). To force orderings of
- * reads before a validation and the validation itself in those
- * cases where this is not already forced, we use
- * Unsafe.loadFence.
- *
- * The memory layout keeps lock state and queue pointers together
- * (normally on the same cache line). This usually works well for
- * read-mostly loads. In most other cases, the natural tendency of
- * adaptive-spin CLH locks to reduce memory contention lessens
- * motivation to further spread out contended locations, but might
- * be subject to future improvements.
- */
-
- private static final long serialVersionUID = -6001602636862214147L;
-
- /** Number of processors, for spin control */
- private static final int NCPU = Runtime.getRuntime().availableProcessors();
-
- /** Maximum number of retries before enqueuing on acquisition */
- private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
-
- /** Maximum number of retries before blocking at head on acquisition */
- private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
-
- /** Maximum number of retries before re-blocking */
- private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
-
- /** The period for yielding when waiting for overflow spinlock */
- private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
-
- /** The number of bits to use for reader count before overflowing */
- private static final int LG_READERS = 7;
-
- // Values for lock state and stamp operations
- private static final long RUNIT = 1L;
- private static final long WBIT = 1L << LG_READERS;
- private static final long RBITS = WBIT - 1L;
- private static final long RFULL = RBITS - 1L;
- private static final long ABITS = RBITS | WBIT;
- private static final long SBITS = ~RBITS; // note overlap with ABITS
-
- // Initial value for lock state; avoid failure value zero
- private static final long ORIGIN = WBIT << 1;
-
- // Special value from cancelled acquire methods so caller can throw IE
- private static final long INTERRUPTED = 1L;
-
- // Values for node status; order matters
- private static final int WAITING = -1;
- private static final int CANCELLED = 1;
-
- // Modes for nodes (int not boolean to allow arithmetic)
- private static final int RMODE = 0;
- private static final int WMODE = 1;
-
- /** Wait nodes */
- static final class WNode {
- volatile WNode prev;
- volatile WNode next;
- volatile WNode cowait; // list of linked readers
- volatile Thread thread; // non-null while possibly parked
- volatile int status; // 0, WAITING, or CANCELLED
- final int mode; // RMODE or WMODE
- WNode(int m, WNode p) { mode = m; prev = p; }
- }
-
- /** Head of CLH queue */
- private transient volatile WNode whead;
- /** Tail (last) of CLH queue */
- private transient volatile WNode wtail;
-
- // views
- transient ReadLockView readLockView;
- transient WriteLockView writeLockView;
- transient ReadWriteLockView readWriteLockView;
-
- /** Lock sequence/state */
- private transient volatile long state;
- /** extra reader count when state read count saturated */
- private transient int readerOverflow;
-
- /**
- * Creates a new lock, initially in unlocked state.
- */
- public StampedLock() {
- state = ORIGIN;
- }
-
- /**
- * Exclusively acquires the lock, blocking if necessary
- * until available.
- *
- * @return a stamp that can be used to unlock or convert mode
- */
- public long writeLock() {
- long s, next; // bypass acquireWrite in fully unlocked case only
- return ((((s = state) & ABITS) == 0L &&
- U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
- next : acquireWrite(false, 0L));
- }
-
- /**
- * Exclusively acquires the lock if it is immediately available.
- *
- * @return a stamp that can be used to unlock or convert mode,
- * or zero if the lock is not available
- */
- public long tryWriteLock() {
- long s, next;
- return ((((s = state) & ABITS) == 0L &&
- U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
- next : 0L);
- }
-
- /**
- * Exclusively acquires the lock if it is available within the
- * given time and the current thread has not been interrupted.
- * Behavior under timeout and interruption matches that specified
- * for method {@link Lock#tryLock(long,TimeUnit)}.
- *
- * @param time the maximum time to wait for the lock
- * @param unit the time unit of the {@code time} argument
- * @return a stamp that can be used to unlock or convert mode,
- * or zero if the lock is not available
- * @throws InterruptedException if the current thread is interrupted
- * before acquiring the lock
- */
- public long tryWriteLock(long time, TimeUnit unit)
- throws InterruptedException {
- long nanos = unit.toNanos(time);
- if (!Thread.interrupted()) {
- long next, deadline;
- if ((next = tryWriteLock()) != 0L)
- return next;
- if (nanos <= 0L)
- return 0L;
- if ((deadline = System.nanoTime() + nanos) == 0L)
- deadline = 1L;
- if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
- return next;
- }
- throw new InterruptedException();
- }
-
- /**
- * Exclusively acquires the lock, blocking if necessary
- * until available or the current thread is interrupted.
- * Behavior under interruption matches that specified
- * for method {@link Lock#lockInterruptibly()}.
- *
- * @return a stamp that can be used to unlock or convert mode
- * @throws InterruptedException if the current thread is interrupted
- * before acquiring the lock
- */
- public long writeLockInterruptibly() throws InterruptedException {
- long next;
- if (!Thread.interrupted() &&
- (next = acquireWrite(true, 0L)) != INTERRUPTED)
- return next;
- throw new InterruptedException();
- }
-
- /**
- * Non-exclusively acquires the lock, blocking if necessary
- * until available.
- *
- * @return a stamp that can be used to unlock or convert mode
- */
- public long readLock() {
- long s = state, next; // bypass acquireRead on common uncontended case
- return ((whead == wtail && (s & ABITS) < RFULL &&
- U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
- next : acquireRead(false, 0L));
- }
-
- /**
- * Non-exclusively acquires the lock if it is immediately available.
- *
- * @return a stamp that can be used to unlock or convert mode,
- * or zero if the lock is not available
- */
- public long tryReadLock() {
- for (;;) {
- long s, m, next;
- if ((m = (s = state) & ABITS) == WBIT)
- return 0L;
- else if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
- return next;
- }
- else if ((next = tryIncReaderOverflow(s)) != 0L)
- return next;
- }
- }
-
- /**
- * Non-exclusively acquires the lock if it is available within the
- * given time and the current thread has not been interrupted.
- * Behavior under timeout and interruption matches that specified
- * for method {@link Lock#tryLock(long,TimeUnit)}.
- *
- * @param time the maximum time to wait for the lock
- * @param unit the time unit of the {@code time} argument
- * @return a stamp that can be used to unlock or convert mode,
- * or zero if the lock is not available
- * @throws InterruptedException if the current thread is interrupted
- * before acquiring the lock
- */
- public long tryReadLock(long time, TimeUnit unit)
- throws InterruptedException {
- long s, m, next, deadline;
- long nanos = unit.toNanos(time);
- if (!Thread.interrupted()) {
- if ((m = (s = state) & ABITS) != WBIT) {
- if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
- return next;
- }
- else if ((next = tryIncReaderOverflow(s)) != 0L)
- return next;
- }
- if (nanos <= 0L)
- return 0L;
- if ((deadline = System.nanoTime() + nanos) == 0L)
- deadline = 1L;
- if ((next = acquireRead(true, deadline)) != INTERRUPTED)
- return next;
- }
- throw new InterruptedException();
- }
-
- /**
- * Non-exclusively acquires the lock, blocking if necessary
- * until available or the current thread is interrupted.
- * Behavior under interruption matches that specified
- * for method {@link Lock#lockInterruptibly()}.
- *
- * @return a stamp that can be used to unlock or convert mode
- * @throws InterruptedException if the current thread is interrupted
- * before acquiring the lock
- */
- public long readLockInterruptibly() throws InterruptedException {
- long next;
- if (!Thread.interrupted() &&
- (next = acquireRead(true, 0L)) != INTERRUPTED)
- return next;
- throw new InterruptedException();
- }
-
- /**
- * Returns a stamp that can later be validated, or zero
- * if exclusively locked.
- *
- * @return a stamp, or zero if exclusively locked
- */
- public long tryOptimisticRead() {
- long s;
- return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
- }
-
- /**
- * Returns true if the lock has not been exclusively acquired
- * since issuance of the given stamp. Always returns false if the
- * stamp is zero. Always returns true if the stamp represents a
- * currently held lock. Invoking this method with a value not
- * obtained from {@link #tryOptimisticRead} or a locking method
- * for this lock has no defined effect or result.
- *
- * @param stamp a stamp
- * @return {@code true} if the lock has not been exclusively acquired
- * since issuance of the given stamp; else false
- */
- public boolean validate(long stamp) {
- U.loadFence();
- return (stamp & SBITS) == (state & SBITS);
- }
-
- /**
- * If the lock state matches the given stamp, releases the
- * exclusive lock.
- *
- * @param stamp a stamp returned by a write-lock operation
- * @throws IllegalMonitorStateException if the stamp does
- * not match the current state of this lock
- */
- public void unlockWrite(long stamp) {
- WNode h;
- if (state != stamp || (stamp & WBIT) == 0L)
- throw new IllegalMonitorStateException();
- U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
- if ((h = whead) != null && h.status != 0)
- release(h);
- }
-
- /**
- * If the lock state matches the given stamp, releases the
- * non-exclusive lock.
- *
- * @param stamp a stamp returned by a read-lock operation
- * @throws IllegalMonitorStateException if the stamp does
- * not match the current state of this lock
- */
- public void unlockRead(long stamp) {
- long s, m; WNode h;
- for (;;) {
- if (((s = state) & SBITS) != (stamp & SBITS) ||
- (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
- throw new IllegalMonitorStateException();
- if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
- if (m == RUNIT && (h = whead) != null && h.status != 0)
- release(h);
- break;
- }
- }
- else if (tryDecReaderOverflow(s) != 0L)
- break;
- }
- }
-
- /**
- * If the lock state matches the given stamp, releases the
- * corresponding mode of the lock.
- *
- * @param stamp a stamp returned by a lock operation
- * @throws IllegalMonitorStateException if the stamp does
- * not match the current state of this lock
- */
- public void unlock(long stamp) {
- long a = stamp & ABITS, m, s; WNode h;
- while (((s = state) & SBITS) == (stamp & SBITS)) {
- if ((m = s & ABITS) == 0L)
- break;
- else if (m == WBIT) {
- if (a != m)
- break;
- U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
- if ((h = whead) != null && h.status != 0)
- release(h);
- return;
- }
- else if (a == 0L || a >= WBIT)
- break;
- else if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
- if (m == RUNIT && (h = whead) != null && h.status != 0)
- release(h);
- return;
- }
- }
- else if (tryDecReaderOverflow(s) != 0L)
- return;
- }
- throw new IllegalMonitorStateException();
- }
-
- /**
- * If the lock state matches the given stamp, atomically performs one of
- * the following actions. If the stamp represents holding a write
- * lock, returns it. Or, if a read lock, if the write lock is
- * available, releases the read lock and returns a write stamp.
- * Or, if an optimistic read, returns a write stamp only if
- * immediately available. This method returns zero in all other
- * cases.
- *
- * @param stamp a stamp
- * @return a valid write stamp, or zero on failure
- */
- public long tryConvertToWriteLock(long stamp) {
- long a = stamp & ABITS, m, s, next;
- while (((s = state) & SBITS) == (stamp & SBITS)) {
- if ((m = s & ABITS) == 0L) {
- if (a != 0L)
- break;
- if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
- return next;
- }
- else if (m == WBIT) {
- if (a != m)
- break;
- return stamp;
- }
- else if (m == RUNIT && a != 0L) {
- if (U.compareAndSwapLong(this, STATE, s,
- next = s - RUNIT + WBIT))
- return next;
- }
- else
- break;
- }
- return 0L;
- }
-
- /**
- * If the lock state matches the given stamp, atomically performs one of
- * the following actions. If the stamp represents holding a write
- * lock, releases it and obtains a read lock. Or, if a read lock,
- * returns it. Or, if an optimistic read, acquires a read lock and
- * returns a read stamp only if immediately available. This method
- * returns zero in all other cases.
- *
- * @param stamp a stamp
- * @return a valid read stamp, or zero on failure
- */
- public long tryConvertToReadLock(long stamp) {
- long a = stamp & ABITS, m, s, next; WNode h;
- while (((s = state) & SBITS) == (stamp & SBITS)) {
- if ((m = s & ABITS) == 0L) {
- if (a != 0L)
- break;
- else if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
- return next;
- }
- else if ((next = tryIncReaderOverflow(s)) != 0L)
- return next;
- }
- else if (m == WBIT) {
- if (a != m)
- break;
- U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
- if ((h = whead) != null && h.status != 0)
- release(h);
- return next;
- }
- else if (a != 0L && a < WBIT)
- return stamp;
- else
- break;
- }
- return 0L;
- }
-
- /**
- * If the lock state matches the given stamp then, atomically, if the stamp
- * represents holding a lock, releases it and returns an
- * observation stamp. Or, if an optimistic read, returns it if
- * validated. This method returns zero in all other cases, and so
- * may be useful as a form of "tryUnlock".
- *
- * @param stamp a stamp
- * @return a valid optimistic read stamp, or zero on failure
- */
- public long tryConvertToOptimisticRead(long stamp) {
- long a = stamp & ABITS, m, s, next; WNode h;
- U.loadFence();
- for (;;) {
- if (((s = state) & SBITS) != (stamp & SBITS))
- break;
- if ((m = s & ABITS) == 0L) {
- if (a != 0L)
- break;
- return s;
- }
- else if (m == WBIT) {
- if (a != m)
- break;
- U.putLongVolatile(this, STATE,
- next = (s += WBIT) == 0L ? ORIGIN : s);
- if ((h = whead) != null && h.status != 0)
- release(h);
- return next;
- }
- else if (a == 0L || a >= WBIT)
- break;
- else if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
- if (m == RUNIT && (h = whead) != null && h.status != 0)
- release(h);
- return next & SBITS;
- }
- }
- else if ((next = tryDecReaderOverflow(s)) != 0L)
- return next & SBITS;
- }
- return 0L;
- }
-
- /**
- * Releases the write lock if it is held, without requiring a
- * stamp value. This method may be useful for recovery after
- * errors.
- *
- * @return {@code true} if the lock was held, else false
- */
- public boolean tryUnlockWrite() {
- long s; WNode h;
- if (((s = state) & WBIT) != 0L) {
- U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
- if ((h = whead) != null && h.status != 0)
- release(h);
- return true;
- }
- return false;
- }
-
- /**
- * Releases one hold of the read lock if it is held, without
- * requiring a stamp value. This method may be useful for recovery
- * after errors.
- *
- * @return {@code true} if the read lock was held, else false
- */
- public boolean tryUnlockRead() {
- long s, m; WNode h;
- while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
- if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
- if (m == RUNIT && (h = whead) != null && h.status != 0)
- release(h);
- return true;
- }
- }
- else if (tryDecReaderOverflow(s) != 0L)
- return true;
- }
- return false;
- }
-
- // status monitoring methods
-
- /**
- * Returns combined state-held and overflow read count for given
- * state s.
- */
- private int getReadLockCount(long s) {
- long readers;
- if ((readers = s & RBITS) >= RFULL)
- readers = RFULL + readerOverflow;
- return (int) readers;
- }
-
- /**
- * Returns {@code true} if the lock is currently held exclusively.
- *
- * @return {@code true} if the lock is currently held exclusively
- */
- public boolean isWriteLocked() {
- return (state & WBIT) != 0L;
- }
-
- /**
- * Returns {@code true} if the lock is currently held non-exclusively.
- *
- * @return {@code true} if the lock is currently held non-exclusively
- */
- public boolean isReadLocked() {
- return (state & RBITS) != 0L;
- }
-
- /**
- * Queries the number of read locks held for this lock. This
- * method is designed for use in monitoring system state, not for
- * synchronization control.
- * @return the number of read locks held
- */
- public int getReadLockCount() {
- return getReadLockCount(state);
- }
-
- /**
- * Returns a string identifying this lock, as well as its lock
- * state. The state, in brackets, includes the String {@code
- * "Unlocked"} or the String {@code "Write-locked"} or the String
- * {@code "Read-locks:"} followed by the current number of
- * read-locks held.
- *
- * @return a string identifying this lock, as well as its lock state
- */
- public String toString() {
- long s = state;
- return super.toString() +
- ((s & ABITS) == 0L ? "[Unlocked]" :
- (s & WBIT) != 0L ? "[Write-locked]" :
- "[Read-locks:" + getReadLockCount(s) + "]");
- }
-
- // views
-
- /**
- * Returns a plain {@link Lock} view of this StampedLock in which
- * the {@link Lock#lock} method is mapped to {@link #readLock},
- * and similarly for other methods. The returned Lock does not
- * support a {@link Condition}; method {@link
- * Lock#newCondition()} throws {@code
- * UnsupportedOperationException}.
- *
- * @return the lock
- */
- public Lock asReadLock() {
- ReadLockView v;
- return ((v = readLockView) != null ? v :
- (readLockView = new ReadLockView()));
- }
-
- /**
- * Returns a plain {@link Lock} view of this StampedLock in which
- * the {@link Lock#lock} method is mapped to {@link #writeLock},
- * and similarly for other methods. The returned Lock does not
- * support a {@link Condition}; method {@link
- * Lock#newCondition()} throws {@code
- * UnsupportedOperationException}.
- *
- * @return the lock
- */
- public Lock asWriteLock() {
- WriteLockView v;
- return ((v = writeLockView) != null ? v :
- (writeLockView = new WriteLockView()));
- }
-
- /**
- * Returns a {@link ReadWriteLock} view of this StampedLock in
- * which the {@link ReadWriteLock#readLock()} method is mapped to
- * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to
- * {@link #asWriteLock()}.
- *
- * @return the lock
- */
- public ReadWriteLock asReadWriteLock() {
- ReadWriteLockView v;
- return ((v = readWriteLockView) != null ? v :
- (readWriteLockView = new ReadWriteLockView()));
- }
-
- // view classes
-
- final class ReadLockView implements Lock {
- public void lock() { readLock(); }
- public void lockInterruptibly() throws InterruptedException {
- readLockInterruptibly();
- }
- public boolean tryLock() { return tryReadLock() != 0L; }
- public boolean tryLock(long time, TimeUnit unit)
- throws InterruptedException {
- return tryReadLock(time, unit) != 0L;
- }
- public void unlock() { unstampedUnlockRead(); }
- public Condition newCondition() {
- throw new UnsupportedOperationException();
- }
- }
-
- final class WriteLockView implements Lock {
- public void lock() { writeLock(); }
- public void lockInterruptibly() throws InterruptedException {
- writeLockInterruptibly();
- }
- public boolean tryLock() { return tryWriteLock() != 0L; }
- public boolean tryLock(long time, TimeUnit unit)
- throws InterruptedException {
- return tryWriteLock(time, unit) != 0L;
- }
- public void unlock() { unstampedUnlockWrite(); }
- public Condition newCondition() {
- throw new UnsupportedOperationException();
- }
- }
-
- final class ReadWriteLockView implements ReadWriteLock {
- public Lock readLock() { return asReadLock(); }
- public Lock writeLock() { return asWriteLock(); }
- }
-
- // Unlock methods without stamp argument checks for view classes.
- // Needed because view-class lock methods throw away stamps.
-
- final void unstampedUnlockWrite() {
- WNode h; long s;
- if (((s = state) & WBIT) == 0L)
- throw new IllegalMonitorStateException();
- U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
- if ((h = whead) != null && h.status != 0)
- release(h);
- }
-
- final void unstampedUnlockRead() {
- for (;;) {
- long s, m; WNode h;
- if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
- throw new IllegalMonitorStateException();
- else if (m < RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
- if (m == RUNIT && (h = whead) != null && h.status != 0)
- release(h);
- break;
- }
- }
- else if (tryDecReaderOverflow(s) != 0L)
- break;
- }
- }
-
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
- }
-
- // internals
-
- /**
- * Tries to increment readerOverflow by first setting state
- * access bits value to RBITS, indicating hold of spinlock,
- * then updating, then releasing.
- *
- * @param s a reader overflow stamp: (s & ABITS) >= RFULL
- * @return new stamp on success, else zero
- */
- private long tryIncReaderOverflow(long s) {
- // assert (s & ABITS) >= RFULL;
- if ((s & ABITS) == RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
- ++readerOverflow;
- U.putLongVolatile(this, STATE, s);
- return s;
- }
- }
- else if ((LockSupport.nextSecondarySeed() &
- OVERFLOW_YIELD_RATE) == 0)
- Thread.yield();
- return 0L;
- }
-
- /**
- * Tries to decrement readerOverflow.
- *
- * @param s a reader overflow stamp: (s & ABITS) >= RFULL
- * @return new stamp on success, else zero
- */
- private long tryDecReaderOverflow(long s) {
- // assert (s & ABITS) >= RFULL;
- if ((s & ABITS) == RFULL) {
- if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
- int r; long next;
- if ((r = readerOverflow) > 0) {
- readerOverflow = r - 1;
- next = s;
- }
- else
- next = s - RUNIT;
- U.putLongVolatile(this, STATE, next);
- return next;
- }
- }
- else if ((LockSupport.nextSecondarySeed() &
- OVERFLOW_YIELD_RATE) == 0)
- Thread.yield();
- return 0L;
- }
-
- /**
- * Wakes up the successor of h (normally whead). This is normally
- * just h.next, but may require traversal from wtail if next
- * pointers are lagging. This may fail to wake up an acquiring
- * thread when one or more have been cancelled, but the cancel
- * methods themselves provide extra safeguards to ensure liveness.
- */
- private void release(WNode h) {
- if (h != null) {
- WNode q; Thread w;
- U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
- if ((q = h.next) == null || q.status == CANCELLED) {
- for (WNode t = wtail; t != null && t != h; t = t.prev)
- if (t.status <= 0)
- q = t;
- }
- if (q != null && (w = q.thread) != null)
- U.unpark(w);
- }
- }
-
- /**
- * See above for explanation.
- *
- * @param interruptible true if should check interrupts and if so
- * return INTERRUPTED
- * @param deadline if nonzero, the System.nanoTime value to timeout
- * at (and return zero)
- * @return next state, or INTERRUPTED
- */
- private long acquireWrite(boolean interruptible, long deadline) {
- WNode node = null, p;
- for (int spins = -1;;) { // spin while enqueuing
- long m, s, ns;
- if ((m = (s = state) & ABITS) == 0L) {
- if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
- return ns;
- }
- else if (spins < 0)
- spins = (m == WBIT && wtail == whead) ? SPINS : 0;
- else if (spins > 0) {
- if (LockSupport.nextSecondarySeed() >= 0)
- --spins;
- }
- else if ((p = wtail) == null) { // initialize queue
- WNode hd = new WNode(WMODE, null);
- if (U.compareAndSwapObject(this, WHEAD, null, hd))
- wtail = hd;
- }
- else if (node == null)
- node = new WNode(WMODE, p);
- else if (node.prev != p)
- node.prev = p;
- else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
- p.next = node;
- break;
- }
- }
-
- boolean wasInterrupted = false;
- for (int spins = -1;;) {
- WNode h, np, pp; int ps;
- if ((h = whead) == p) {
- if (spins < 0)
- spins = HEAD_SPINS;
- else if (spins < MAX_HEAD_SPINS)
- spins <<= 1;
- for (int k = spins;;) { // spin at head
- long s, ns;
- if (((s = state) & ABITS) == 0L) {
- if (U.compareAndSwapLong(this, STATE, s,
- ns = s + WBIT)) {
- whead = node;
- node.prev = null;
- if (wasInterrupted)
- Thread.currentThread().interrupt();
- return ns;
- }
- }
- else if (LockSupport.nextSecondarySeed() >= 0 &&
- --k <= 0)
- break;
- }
- }
- else if (h != null) { // help release stale waiters
- WNode c; Thread w;
- while ((c = h.cowait) != null) {
- if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
- (w = c.thread) != null)
- U.unpark(w);
- }
- }
- if (whead == h) {
- if ((np = node.prev) != p) {
- if (np != null)
- (p = np).next = node; // stale
- }
- else if ((ps = p.status) == 0)
- U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
- else if (ps == CANCELLED) {
- if ((pp = p.prev) != null) {
- node.prev = pp;
- pp.next = node;
- }
- }
- else {
- long time; // 0 argument to park means no timeout
- if (deadline == 0L)
- time = 0L;
- else if ((time = deadline - System.nanoTime()) <= 0L)
- return cancelWaiter(node, node, false);
- Thread wt = Thread.currentThread();
- U.putObject(wt, PARKBLOCKER, this);
- node.thread = wt;
- if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
- whead == h && node.prev == p)
- U.park(false, time); // emulate LockSupport.park
- node.thread = null;
- U.putObject(wt, PARKBLOCKER, null);
- if (Thread.interrupted()) {
- if (interruptible)
- return cancelWaiter(node, node, true);
- wasInterrupted = true;
- }
- }
- }
- }
- }
-
- /**
- * See above for explanation.
- *
- * @param interruptible true if should check interrupts and if so
- * return INTERRUPTED
- * @param deadline if nonzero, the System.nanoTime value to timeout
- * at (and return zero)
- * @return next state, or INTERRUPTED
- */
- private long acquireRead(boolean interruptible, long deadline) {
- boolean wasInterrupted = false;
- WNode node = null, p;
- for (int spins = -1;;) {
- WNode h;
- if ((h = whead) == (p = wtail)) {
- for (long m, s, ns;;) {
- if ((m = (s = state) & ABITS) < RFULL ?
- U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
- (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
- if (wasInterrupted)
- Thread.currentThread().interrupt();
- return ns;
- }
- else if (m >= WBIT) {
- if (spins > 0) {
- if (LockSupport.nextSecondarySeed() >= 0)
- --spins;
- }
- else {
- if (spins == 0) {
- WNode nh = whead, np = wtail;
- if ((nh == h && np == p) || (h = nh) != (p = np))
- break;
- }
- spins = SPINS;
- }
- }
- }
- }
- if (p == null) { // initialize queue
- WNode hd = new WNode(WMODE, null);
- if (U.compareAndSwapObject(this, WHEAD, null, hd))
- wtail = hd;
- }
- else if (node == null)
- node = new WNode(RMODE, p);
- else if (h == p || p.mode != RMODE) {
- if (node.prev != p)
- node.prev = p;
- else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
- p.next = node;
- break;
- }
- }
- else if (!U.compareAndSwapObject(p, WCOWAIT,
- node.cowait = p.cowait, node))
- node.cowait = null;
- else {
- for (;;) {
- WNode pp, c; Thread w;
- if ((h = whead) != null && (c = h.cowait) != null &&
- U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
- (w = c.thread) != null) // help release
- U.unpark(w);
- if (h == (pp = p.prev) || h == p || pp == null) {
- long m, s, ns;
- do {
- if ((m = (s = state) & ABITS) < RFULL ?
- U.compareAndSwapLong(this, STATE, s,
- ns = s + RUNIT) :
- (m < WBIT &&
- (ns = tryIncReaderOverflow(s)) != 0L)) {
- if (wasInterrupted)
- Thread.currentThread().interrupt();
- return ns;
- }
- } while (m < WBIT);
- }
- if (whead == h && p.prev == pp) {
- long time;
- if (pp == null || h == p || p.status > 0) {
- node = null; // throw away
- break;
- }
- if (deadline == 0L)
- time = 0L;
- else if ((time = deadline - System.nanoTime()) <= 0L) {
- if (wasInterrupted)
- Thread.currentThread().interrupt();
- return cancelWaiter(node, p, false);
- }
- Thread wt = Thread.currentThread();
- U.putObject(wt, PARKBLOCKER, this);
- node.thread = wt;
- if ((h != pp || (state & ABITS) == WBIT) &&
- whead == h && p.prev == pp)
- U.park(false, time);
- node.thread = null;
- U.putObject(wt, PARKBLOCKER, null);
- if (Thread.interrupted()) {
- if (interruptible)
- return cancelWaiter(node, p, true);
- wasInterrupted = true;
- }
- }
- }
- }
- }
-
- for (int spins = -1;;) {
- WNode h, np, pp; int ps;
- if ((h = whead) == p) {
- if (spins < 0)
- spins = HEAD_SPINS;
- else if (spins < MAX_HEAD_SPINS)
- spins <<= 1;
- for (int k = spins;;) { // spin at head
- long m, s, ns;
- if ((m = (s = state) & ABITS) < RFULL ?
- U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
- (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
- WNode c; Thread w;
- whead = node;
- node.prev = null;
- while ((c = node.cowait) != null) {
- if (U.compareAndSwapObject(node, WCOWAIT,
- c, c.cowait) &&
- (w = c.thread) != null)
- U.unpark(w);
- }
- if (wasInterrupted)
- Thread.currentThread().interrupt();
- return ns;
- }
- else if (m >= WBIT &&
- LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
- break;
- }
- }
- else if (h != null) {
- WNode c; Thread w;
- while ((c = h.cowait) != null) {
- if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
- (w = c.thread) != null)
- U.unpark(w);
- }
- }
- if (whead == h) {
- if ((np = node.prev) != p) {
- if (np != null)
- (p = np).next = node; // stale
- }
- else if ((ps = p.status) == 0)
- U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
- else if (ps == CANCELLED) {
- if ((pp = p.prev) != null) {
- node.prev = pp;
- pp.next = node;
- }
- }
- else {
- long time;
- if (deadline == 0L)
- time = 0L;
- else if ((time = deadline - System.nanoTime()) <= 0L)
- return cancelWaiter(node, node, false);
- Thread wt = Thread.currentThread();
- U.putObject(wt, PARKBLOCKER, this);
- node.thread = wt;
- if (p.status < 0 &&
- (p != h || (state & ABITS) == WBIT) &&
- whead == h && node.prev == p)
- U.park(false, time);
- node.thread = null;
- U.putObject(wt, PARKBLOCKER, null);
- if (Thread.interrupted()) {
- if (interruptible)
- return cancelWaiter(node, node, true);
- wasInterrupted = true;
- }
- }
- }
- }
- }
-
- /**
- * If node non-null, forces cancel status and unsplices it from
- * queue if possible and wakes up any cowaiters (of the node, or
- * group, as applicable), and in any case helps release current
- * first waiter if lock is free. (Calling with null arguments
- * serves as a conditional form of release, which is not currently
- * needed but may be needed under possible future cancellation
- * policies). This is a variant of cancellation methods in
- * AbstractQueuedSynchronizer (see its detailed explanation in AQS
- * internal documentation).
- *
- * @param node if nonnull, the waiter
- * @param group either node or the group node is cowaiting with
- * @param interrupted if already interrupted
- * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
- */
- private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
- if (node != null && group != null) {
- Thread w;
- node.status = CANCELLED;
- // unsplice cancelled nodes from group
- for (WNode p = group, q; (q = p.cowait) != null;) {
- if (q.status == CANCELLED) {
- U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
- p = group; // restart
- }
- else
- p = q;
- }
- if (group == node) {
- for (WNode r = group.cowait; r != null; r = r.cowait) {
- if ((w = r.thread) != null)
- U.unpark(w); // wake up uncancelled co-waiters
- }
- for (WNode pred = node.prev; pred != null; ) { // unsplice
- WNode succ, pp; // find valid successor
- while ((succ = node.next) == null ||
- succ.status == CANCELLED) {
- WNode q = null; // find successor the slow way
- for (WNode t = wtail; t != null && t != node; t = t.prev)
- if (t.status != CANCELLED)
- q = t; // don't link if succ cancelled
- if (succ == q || // ensure accurate successor
- U.compareAndSwapObject(node, WNEXT,
- succ, succ = q)) {
- if (succ == null && node == wtail)
- U.compareAndSwapObject(this, WTAIL, node, pred);
- break;
- }
- }
- if (pred.next == node) // unsplice pred link
- U.compareAndSwapObject(pred, WNEXT, node, succ);
- if (succ != null && (w = succ.thread) != null) {
- succ.thread = null;
- U.unpark(w); // wake up succ to observe new pred
- }
- if (pred.status != CANCELLED || (pp = pred.prev) == null)
- break;
- node.prev = pp; // repeat if new pred wrong/cancelled
- U.compareAndSwapObject(pp, WNEXT, pred, succ);
- pred = pp;
- }
- }
- }
- WNode h; // Possibly release first waiter
- while ((h = whead) != null) {
- long s; WNode q; // similar to release() but check eligibility
- if ((q = h.next) == null || q.status == CANCELLED) {
- for (WNode t = wtail; t != null && t != h; t = t.prev)
- if (t.status <= 0)
- q = t;
- }
- if (h == whead) {
- if (q != null && h.status == 0 &&
- ((s = state) & ABITS) != WBIT && // waiter is eligible
- (s == 0L || q.mode == RMODE))
- release(h);
- break;
- }
- }
- return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long WHEAD;
- private static final long WTAIL;
- private static final long WNEXT;
- private static final long WSTATUS;
- private static final long WCOWAIT;
- private static final long PARKBLOCKER;
-
- static {
- try {
- STATE = U.objectFieldOffset
- (StampedLock.class.getDeclaredField("state"));
- WHEAD = U.objectFieldOffset
- (StampedLock.class.getDeclaredField("whead"));
- WTAIL = U.objectFieldOffset
- (StampedLock.class.getDeclaredField("wtail"));
-
- WSTATUS = U.objectFieldOffset
- (WNode.class.getDeclaredField("status"));
- WNEXT = U.objectFieldOffset
- (WNode.class.getDeclaredField("next"));
- WCOWAIT = U.objectFieldOffset
- (WNode.class.getDeclaredField("cowait"));
-
- PARKBLOCKER = U.objectFieldOffset
- (Thread.class.getDeclaredField("parkBlocker"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/package-info.java b/luni/src/main/java/java/util/concurrent/package-info.java
index 5dc1228..afc8ca4 100644
--- a/luni/src/main/java/java/util/concurrent/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/package-info.java
@@ -181,25 +181,18 @@
* collections are unshared, or are accessible only when
* holding other locks.
*
- * <p id="Weakly">Most concurrent Collection implementations
- * (including most Queues) also differ from the usual {@code java.util}
- * conventions in that their {@linkplain java.util.Iterator Iterators}
- * and {@linkplain java.util.Spliterator Spliterators} provide
- * <em>weakly consistent</em> rather than fast-fail traversal:
- * <ul>
- * <li>they may proceed concurrently with other operations
- * <li>they will never throw {@link java.util.ConcurrentModificationException
- * ConcurrentModificationException}
- * <li>they are guaranteed to traverse elements as they existed upon
- * construction exactly once, and may (but are not guaranteed to)
- * reflect any modifications subsequent to construction.
- * </ul>
+ * <p>Most concurrent Collection implementations (including most
+ * Queues) also differ from the usual java.util conventions in that
+ * their Iterators provide <em>weakly consistent</em> rather than
+ * fast-fail traversal. A weakly consistent iterator is thread-safe,
+ * but does not necessarily freeze the collection while iterating, so
+ * it may (or may not) reflect any updates since the iterator was
+ * created.
*
* <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
*
- * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5">
- * Chapter 17 of
- * <cite>The Java™ Language Specification</cite></a> defines the
+ * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5">
+ * Chapter 17 of the Java Language Specification</a> defines the
* <i>happens-before</i> relation on memory operations such as reads and
* writes of shared variables. The results of a write by one thread are
* guaranteed to be visible to a read by another thread only if the write
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index 104a6f3..0c5502b 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -88,10 +88,7 @@
luni/src/main/java/java/util/concurrent/BrokenBarrierException.java \
luni/src/main/java/java/util/concurrent/Callable.java \
luni/src/main/java/java/util/concurrent/CancellationException.java \
- luni/src/main/java/java/util/concurrent/CompletableFuture.java \
- luni/src/main/java/java/util/concurrent/CompletionException.java \
luni/src/main/java/java/util/concurrent/CompletionService.java \
- luni/src/main/java/java/util/concurrent/CompletionStage.java \
luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java \
luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java \
luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java \
@@ -117,7 +114,6 @@
luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java \
luni/src/main/java/java/util/concurrent/Future.java \
luni/src/main/java/java/util/concurrent/FutureTask.java \
- luni/src/main/java/java/util/concurrent/Helpers.java \
luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java \
luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java \
luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java \
@@ -152,11 +148,7 @@
luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java \
luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java \
luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java \
- luni/src/main/java/java/util/concurrent/atomic/DoubleAccumulator.java \
- luni/src/main/java/java/util/concurrent/atomic/DoubleAdder.java \
- luni/src/main/java/java/util/concurrent/atomic/LongAccumulator.java \
- luni/src/main/java/java/util/concurrent/atomic/LongAdder.java \
- luni/src/main/java/java/util/concurrent/atomic/Striped64.java \
+ luni/src/main/java/java/util/concurrent/atomic/Fences.java \
luni/src/main/java/java/util/concurrent/atomic/package-info.java \
luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java \
luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java \
@@ -167,7 +159,6 @@
luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java \
luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java \
luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java \
- luni/src/main/java/java/util/concurrent/locks/StampedLock.java \
luni/src/main/java/java/util/concurrent/locks/package-info.java \
luni/src/main/java/java/util/concurrent/package-info.java \
luni/src/main/java/javax/xml/XMLConstants.java \
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index c14022b..2afeccf 100755
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -2050,25 +2050,6 @@
}
}
-
- // The following three initially uninitialized fields are exclusively
- // managed by class java.util.concurrent.ThreadLocalRandom. These
- // fields are used to build the high-performance PRNGs in the
- // concurrent code, and we can not risk accidental false sharing.
- // Hence, the fields are isolated with @Contended.
-
- /** The current seed for a ThreadLocalRandom */
- // @sun.misc.Contended("tlr")
- long threadLocalRandomSeed;
-
- /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
- // @sun.misc.Contended("tlr")
- int threadLocalRandomProbe;
-
- /** Secondary seed isolated from public ThreadLocalRandom sequence */
- // @sun.misc.Contended("tlr")
- int threadLocalRandomSecondarySeed;
-
/* Some private helper methods */
private native void nativeSetName(String newName);
diff --git a/ojluni/src/main/java/java/util/AbstractQueue.java b/ojluni/src/main/java/java/util/AbstractQueue.java
index 44e11f7..ebe2700 100644
--- a/ojluni/src/main/java/java/util/AbstractQueue.java
+++ b/ojluni/src/main/java/java/util/AbstractQueue.java
@@ -58,7 +58,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public abstract class AbstractQueue<E>
extends AbstractCollection<E>
diff --git a/ojluni/src/main/java/java/util/ArrayDeque.java b/ojluni/src/main/java/java/util/ArrayDeque.java
index 83ae076..eb31bcc 100644
--- a/ojluni/src/main/java/java/util/ArrayDeque.java
+++ b/ojluni/src/main/java/java/util/ArrayDeque.java
@@ -33,7 +33,7 @@
package java.util;
-import java.io.Serializable;
+import java.io.*;
import java.util.function.Consumer;
// BEGIN android-note
@@ -81,10 +81,10 @@
*
* @author Josh Bloch and Doug Lea
* @since 1.6
- * @param <E> the type of elements held in this deque
+ * @param <E> the type of elements held in this collection
*/
public class ArrayDeque<E> extends AbstractCollection<E>
- implements Deque<E>, Cloneable, Serializable
+ implements Deque<E>, Cloneable, java.io.Serializable
{
/**
* The array in which the elements of the deque are stored.
@@ -96,20 +96,20 @@
* other. We also guarantee that all array cells not holding
* deque elements are always null.
*/
- transient Object[] elements; // non-private to simplify nested class access
+ private transient Object[] elements;
/**
* The index of the element at the head of the deque (which is the
* element that would be removed by remove() or pop()); or an
* arbitrary number equal to tail if the deque is empty.
*/
- transient int head;
+ private transient int head;
/**
* The index at which the next element would be added to the tail
* of the deque (via addLast(E), add(E), or push(E)).
*/
- transient int tail;
+ private transient int tail;
/**
* The minimum capacity that we'll use for a newly created deque.
@@ -137,8 +137,8 @@
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
- if (initialCapacity < 0) // Too many elements, must back off
- initialCapacity >>>= 1; // Good luck allocating 2^30 elements
+ if (initialCapacity < 0) // Too many elements, must back off
+ initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
}
elements = new Object[initialCapacity];
}
@@ -275,27 +275,25 @@
}
public E pollFirst() {
- final Object[] elements = this.elements;
- final int h = head;
+ int h = head;
@SuppressWarnings("unchecked")
E result = (E) elements[h];
// Element is null if deque empty
- if (result != null) {
- elements[h] = null; // Must null out slot
- head = (h + 1) & (elements.length - 1);
- }
+ if (result == null)
+ return null;
+ elements[h] = null; // Must null out slot
+ head = (h + 1) & (elements.length - 1);
return result;
}
public E pollLast() {
- final Object[] elements = this.elements;
- final int t = (tail - 1) & (elements.length - 1);
+ int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
- if (result != null) {
- elements[t] = null;
- tail = t;
- }
+ if (result == null)
+ return null;
+ elements[t] = null;
+ tail = t;
return result;
}
@@ -345,15 +343,17 @@
* @return {@code true} if the deque contained the specified element
*/
public boolean removeFirstOccurrence(Object o) {
- if (o != null) {
- int mask = elements.length - 1;
- int i = head;
- for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
- if (o.equals(x)) {
- delete(i);
- return true;
- }
+ if (o == null)
+ return false;
+ int mask = elements.length - 1;
+ int i = head;
+ Object x;
+ while ( (x = elements[i]) != null) {
+ if (o.equals(x)) {
+ delete(i);
+ return true;
}
+ i = (i + 1) & mask;
}
return false;
}
@@ -371,15 +371,17 @@
* @return {@code true} if the deque contained the specified element
*/
public boolean removeLastOccurrence(Object o) {
- if (o != null) {
- int mask = elements.length - 1;
- int i = (tail - 1) & mask;
- for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
- if (o.equals(x)) {
- delete(i);
- return true;
- }
+ if (o == null)
+ return false;
+ int mask = elements.length - 1;
+ int i = (tail - 1) & mask;
+ Object x;
+ while ( (x = elements[i]) != null) {
+ if (o.equals(x)) {
+ delete(i);
+ return true;
}
+ i = (i - 1) & mask;
}
return false;
}
@@ -499,11 +501,11 @@
}
private void checkInvariants() {
- assert elements[tail] == null;
- assert head == tail ? elements[head] == null :
- (elements[head] != null &&
- elements[(tail - 1) & (elements.length - 1)] != null);
- assert elements[(head - 1) & (elements.length - 1)] == null;
+ // assert elements[tail] == null;
+ // assert head == tail ? elements[head] == null :
+ // (elements[head] != null &&
+ // elements[(tail - 1) & (elements.length - 1)] != null);
+ // assert elements[(head - 1) & (elements.length - 1)] == null;
}
/**
@@ -516,8 +518,8 @@
*
* @return true if elements moved backwards
*/
- boolean delete(int i) {
- checkInvariants();
+ private boolean delete(int i) {
+ //checkInvariants();
final Object[] elements = this.elements;
final int mask = elements.length - 1;
final int h = head;
@@ -702,13 +704,15 @@
* @return {@code true} if this deque contains the specified element
*/
public boolean contains(Object o) {
- if (o != null) {
- int mask = elements.length - 1;
- int i = head;
- for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
- if (o.equals(x))
- return true;
- }
+ if (o == null)
+ return false;
+ int mask = elements.length - 1;
+ int i = head;
+ Object x;
+ while ( (x = elements[i]) != null) {
+ if (o.equals(x))
+ return true;
+ i = (i + 1) & mask;
}
return false;
}
@@ -721,7 +725,7 @@
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
- * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+ * <p>This method is equivalent to {@link #removeFirstOccurrence}.
*
* @param o element to be removed from this deque, if present
* @return {@code true} if this deque contained the specified element
@@ -794,7 +798,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -852,8 +856,6 @@
/**
* Saves this deque to a stream (that is, serializes it).
*
- * @param s the stream
- * @throws java.io.IOException if an I/O error occurs
* @serialData The current size ({@code int}) of the deque,
* followed by all of its elements (each an object reference) in
* first-to-last order.
@@ -873,10 +875,6 @@
/**
* Reconstitutes this deque 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.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -915,7 +913,7 @@
private int fence; // -1 until first use
private int index; // current index, modified on traverse/split
- /** Creates new spliterator covering the given array and range. */
+ /** Creates new spliterator covering the given array and range */
DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
this.deq = deq;
this.index = origin;
@@ -937,7 +935,7 @@
if (h > t)
t += n;
int m = ((h + t) >>> 1) & (n - 1);
- return new DeqSpliterator<E>(deq, h, index = m);
+ return new DeqSpliterator<>(deq, h, index = m);
}
return null;
}
@@ -962,7 +960,7 @@
throw new NullPointerException();
Object[] a = deq.elements;
int m = a.length - 1, f = getFence(), i = index;
- if (i != f) {
+ if (i != fence) {
@SuppressWarnings("unchecked") E e = (E)a[i];
index = (i + 1) & m;
if (e == null)
diff --git a/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java b/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java
deleted file mode 100644
index d3b5614..0000000
--- a/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * 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;
-
-import java.util.concurrent.CountedCompleter;
-import java.util.concurrent.ForkJoinPool;
-import java.util.function.BinaryOperator;
-import java.util.function.DoubleBinaryOperator;
-import java.util.function.IntBinaryOperator;
-import java.util.function.LongBinaryOperator;
-
-/**
- * ForkJoin tasks to perform Arrays.parallelPrefix operations.
- *
- * @author Doug Lea
- * @since 1.8
- */
-class ArrayPrefixHelpers {
- private ArrayPrefixHelpers() {} // non-instantiable
-
- /*
- * Parallel prefix (aka cumulate, scan) task classes
- * are based loosely on Guy Blelloch's original
- * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html):
- * Keep dividing by two to threshold segment size, and then:
- * Pass 1: Create tree of partial sums for each segment
- * Pass 2: For each segment, cumulate with offset of left sibling
- *
- * This version improves performance within FJ framework mainly by
- * allowing the second pass of ready left-hand sides to proceed
- * even if some right-hand side first passes are still executing.
- * It also combines first and second pass for leftmost segment,
- * and skips the first pass for rightmost segment (whose result is
- * not needed for second pass). It similarly manages to avoid
- * requiring that users supply an identity basis for accumulations
- * by tracking those segments/subtasks for which the first
- * existing element is used as base.
- *
- * Managing this relies on ORing some bits in the pendingCount for
- * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the
- * main phase bit. When false, segments compute only their sum.
- * When true, they cumulate array elements. CUMULATE is set at
- * root at beginning of second pass and then propagated down. But
- * it may also be set earlier for subtrees with lo==0 (the left
- * spine of tree). SUMMED is a one bit join count. For leafs, it
- * is set when summed. For internal nodes, it becomes true when
- * one child is summed. When the second child finishes summing,
- * we then moves up tree to trigger the cumulate phase. FINISHED
- * is also a one bit join count. For leafs, it is set when
- * cumulated. For internal nodes, it becomes true when one child
- * is cumulated. When the second child finishes cumulating, it
- * then moves up tree, completing at the root.
- *
- * To better exploit locality and reduce overhead, the compute
- * method loops starting with the current task, moving if possible
- * to one of its subtasks rather than forking.
- *
- * As usual for this sort of utility, there are 4 versions, that
- * are simple copy/paste/adapt variants of each other. (The
- * double and int versions differ from long version solely by
- * replacing "long" (with case-matching)).
- */
-
- // see above
- static final int CUMULATE = 1;
- static final int SUMMED = 2;
- static final int FINISHED = 4;
-
- /** The smallest subtask array partition size to use as threshold */
- static final int MIN_PARTITION = 16;
-
- static final class CumulateTask<T> extends CountedCompleter<Void> {
- final T[] array;
- final BinaryOperator<T> function;
- CumulateTask<T> left, right;
- T in, out;
- final int lo, hi, origin, fence, threshold;
-
- /** Root task constructor */
- public CumulateTask(CumulateTask<T> parent,
- BinaryOperator<T> function,
- T[] array, int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.lo = this.origin = lo; this.hi = this.fence = hi;
- int p;
- this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
- }
-
- /** Subtask constructor */
- CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function,
- T[] array, int origin, int fence, int threshold,
- int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.origin = origin; this.fence = fence;
- this.threshold = threshold;
- this.lo = lo; this.hi = hi;
- }
-
- public final void compute() {
- final BinaryOperator<T> fn;
- final T[] a;
- if ((fn = this.function) == null || (a = this.array) == null)
- throw new NullPointerException(); // hoist checks
- int th = threshold, org = origin, fnc = fence, l, h;
- CumulateTask<T> t = this;
- outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
- if (h - l > th) {
- CumulateTask<T> lt = t.left, rt = t.right, f;
- if (lt == null) { // first pass
- int mid = (l + h) >>> 1;
- f = rt = t.right =
- new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
- }
- else { // possibly refork
- T pin = t.in;
- lt.in = pin;
- f = t = null;
- if (rt != null) {
- T lout = lt.out;
- rt.in = (l == org ? lout :
- fn.apply(pin, lout));
- for (int c;;) {
- if (((c = rt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
- t = rt;
- break;
- }
- }
- }
- for (int c;;) {
- if (((c = lt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
- if (t != null)
- f = t;
- t = lt;
- break;
- }
- }
- if (t == null)
- break;
- }
- if (f != null)
- f.fork();
- }
- else {
- int state; // Transition to sum, cumulate, or both
- for (int b;;) {
- if (((b = t.getPendingCount()) & FINISHED) != 0)
- break outer; // already done
- state = ((b & CUMULATE) != 0 ? FINISHED :
- (l > org) ? SUMMED : (SUMMED|FINISHED));
- if (t.compareAndSetPendingCount(b, b|state))
- break;
- }
-
- T sum;
- if (state != SUMMED) {
- int first;
- if (l == org) { // leftmost; no in
- sum = a[org];
- first = org + 1;
- }
- else {
- sum = t.in;
- first = l;
- }
- for (int i = first; i < h; ++i) // cumulate
- a[i] = sum = fn.apply(sum, a[i]);
- }
- else if (h < fnc) { // skip rightmost
- sum = a[l];
- for (int i = l + 1; i < h; ++i) // sum only
- sum = fn.apply(sum, a[i]);
- }
- else
- sum = t.in;
- t.out = sum;
- for (CumulateTask<T> par;;) { // propagate
- @SuppressWarnings("unchecked") CumulateTask<T> partmp
- = (CumulateTask<T>)t.getCompleter();
- if ((par = partmp) == null) {
- if ((state & FINISHED) != 0) // enable join
- t.quietlyComplete();
- break outer;
- }
- int b = par.getPendingCount();
- if ((b & state & FINISHED) != 0)
- t = par; // both done
- else if ((b & state & SUMMED) != 0) { // both summed
- int nextState; CumulateTask<T> lt, rt;
- if ((lt = par.left) != null &&
- (rt = par.right) != null) {
- T lout = lt.out;
- par.out = (rt.hi == fnc ? lout :
- fn.apply(lout, rt.out));
- }
- int refork = (((b & CUMULATE) == 0 &&
- par.lo == org) ? CUMULATE : 0);
- if ((nextState = b|state|refork) == b ||
- par.compareAndSetPendingCount(b, nextState)) {
- state = SUMMED; // drop finished
- t = par;
- if (refork != 0)
- par.fork();
- }
- }
- else if (par.compareAndSetPendingCount(b, b|state))
- break outer; // sib not ready
- }
- }
- }
- }
- private static final long serialVersionUID = 5293554502939613543L;
- }
-
- static final class LongCumulateTask extends CountedCompleter<Void> {
- final long[] array;
- final LongBinaryOperator function;
- LongCumulateTask left, right;
- long in, out;
- final int lo, hi, origin, fence, threshold;
-
- /** Root task constructor */
- public LongCumulateTask(LongCumulateTask parent,
- LongBinaryOperator function,
- long[] array, int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.lo = this.origin = lo; this.hi = this.fence = hi;
- int p;
- this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
- }
-
- /** Subtask constructor */
- LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function,
- long[] array, int origin, int fence, int threshold,
- int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.origin = origin; this.fence = fence;
- this.threshold = threshold;
- this.lo = lo; this.hi = hi;
- }
-
- public final void compute() {
- final LongBinaryOperator fn;
- final long[] a;
- if ((fn = this.function) == null || (a = this.array) == null)
- throw new NullPointerException(); // hoist checks
- int th = threshold, org = origin, fnc = fence, l, h;
- LongCumulateTask t = this;
- outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
- if (h - l > th) {
- LongCumulateTask lt = t.left, rt = t.right, f;
- if (lt == null) { // first pass
- int mid = (l + h) >>> 1;
- f = rt = t.right =
- new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
- }
- else { // possibly refork
- long pin = t.in;
- lt.in = pin;
- f = t = null;
- if (rt != null) {
- long lout = lt.out;
- rt.in = (l == org ? lout :
- fn.applyAsLong(pin, lout));
- for (int c;;) {
- if (((c = rt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
- t = rt;
- break;
- }
- }
- }
- for (int c;;) {
- if (((c = lt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
- if (t != null)
- f = t;
- t = lt;
- break;
- }
- }
- if (t == null)
- break;
- }
- if (f != null)
- f.fork();
- }
- else {
- int state; // Transition to sum, cumulate, or both
- for (int b;;) {
- if (((b = t.getPendingCount()) & FINISHED) != 0)
- break outer; // already done
- state = ((b & CUMULATE) != 0 ? FINISHED :
- (l > org) ? SUMMED : (SUMMED|FINISHED));
- if (t.compareAndSetPendingCount(b, b|state))
- break;
- }
-
- long sum;
- if (state != SUMMED) {
- int first;
- if (l == org) { // leftmost; no in
- sum = a[org];
- first = org + 1;
- }
- else {
- sum = t.in;
- first = l;
- }
- for (int i = first; i < h; ++i) // cumulate
- a[i] = sum = fn.applyAsLong(sum, a[i]);
- }
- else if (h < fnc) { // skip rightmost
- sum = a[l];
- for (int i = l + 1; i < h; ++i) // sum only
- sum = fn.applyAsLong(sum, a[i]);
- }
- else
- sum = t.in;
- t.out = sum;
- for (LongCumulateTask par;;) { // propagate
- if ((par = (LongCumulateTask)t.getCompleter()) == null) {
- if ((state & FINISHED) != 0) // enable join
- t.quietlyComplete();
- break outer;
- }
- int b = par.getPendingCount();
- if ((b & state & FINISHED) != 0)
- t = par; // both done
- else if ((b & state & SUMMED) != 0) { // both summed
- int nextState; LongCumulateTask lt, rt;
- if ((lt = par.left) != null &&
- (rt = par.right) != null) {
- long lout = lt.out;
- par.out = (rt.hi == fnc ? lout :
- fn.applyAsLong(lout, rt.out));
- }
- int refork = (((b & CUMULATE) == 0 &&
- par.lo == org) ? CUMULATE : 0);
- if ((nextState = b|state|refork) == b ||
- par.compareAndSetPendingCount(b, nextState)) {
- state = SUMMED; // drop finished
- t = par;
- if (refork != 0)
- par.fork();
- }
- }
- else if (par.compareAndSetPendingCount(b, b|state))
- break outer; // sib not ready
- }
- }
- }
- }
- private static final long serialVersionUID = -5074099945909284273L;
- }
-
- static final class DoubleCumulateTask extends CountedCompleter<Void> {
- final double[] array;
- final DoubleBinaryOperator function;
- DoubleCumulateTask left, right;
- double in, out;
- final int lo, hi, origin, fence, threshold;
-
- /** Root task constructor */
- public DoubleCumulateTask(DoubleCumulateTask parent,
- DoubleBinaryOperator function,
- double[] array, int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.lo = this.origin = lo; this.hi = this.fence = hi;
- int p;
- this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
- }
-
- /** Subtask constructor */
- DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function,
- double[] array, int origin, int fence, int threshold,
- int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.origin = origin; this.fence = fence;
- this.threshold = threshold;
- this.lo = lo; this.hi = hi;
- }
-
- public final void compute() {
- final DoubleBinaryOperator fn;
- final double[] a;
- if ((fn = this.function) == null || (a = this.array) == null)
- throw new NullPointerException(); // hoist checks
- int th = threshold, org = origin, fnc = fence, l, h;
- DoubleCumulateTask t = this;
- outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
- if (h - l > th) {
- DoubleCumulateTask lt = t.left, rt = t.right, f;
- if (lt == null) { // first pass
- int mid = (l + h) >>> 1;
- f = rt = t.right =
- new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
- }
- else { // possibly refork
- double pin = t.in;
- lt.in = pin;
- f = t = null;
- if (rt != null) {
- double lout = lt.out;
- rt.in = (l == org ? lout :
- fn.applyAsDouble(pin, lout));
- for (int c;;) {
- if (((c = rt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
- t = rt;
- break;
- }
- }
- }
- for (int c;;) {
- if (((c = lt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
- if (t != null)
- f = t;
- t = lt;
- break;
- }
- }
- if (t == null)
- break;
- }
- if (f != null)
- f.fork();
- }
- else {
- int state; // Transition to sum, cumulate, or both
- for (int b;;) {
- if (((b = t.getPendingCount()) & FINISHED) != 0)
- break outer; // already done
- state = ((b & CUMULATE) != 0 ? FINISHED :
- (l > org) ? SUMMED : (SUMMED|FINISHED));
- if (t.compareAndSetPendingCount(b, b|state))
- break;
- }
-
- double sum;
- if (state != SUMMED) {
- int first;
- if (l == org) { // leftmost; no in
- sum = a[org];
- first = org + 1;
- }
- else {
- sum = t.in;
- first = l;
- }
- for (int i = first; i < h; ++i) // cumulate
- a[i] = sum = fn.applyAsDouble(sum, a[i]);
- }
- else if (h < fnc) { // skip rightmost
- sum = a[l];
- for (int i = l + 1; i < h; ++i) // sum only
- sum = fn.applyAsDouble(sum, a[i]);
- }
- else
- sum = t.in;
- t.out = sum;
- for (DoubleCumulateTask par;;) { // propagate
- if ((par = (DoubleCumulateTask)t.getCompleter()) == null) {
- if ((state & FINISHED) != 0) // enable join
- t.quietlyComplete();
- break outer;
- }
- int b = par.getPendingCount();
- if ((b & state & FINISHED) != 0)
- t = par; // both done
- else if ((b & state & SUMMED) != 0) { // both summed
- int nextState; DoubleCumulateTask lt, rt;
- if ((lt = par.left) != null &&
- (rt = par.right) != null) {
- double lout = lt.out;
- par.out = (rt.hi == fnc ? lout :
- fn.applyAsDouble(lout, rt.out));
- }
- int refork = (((b & CUMULATE) == 0 &&
- par.lo == org) ? CUMULATE : 0);
- if ((nextState = b|state|refork) == b ||
- par.compareAndSetPendingCount(b, nextState)) {
- state = SUMMED; // drop finished
- t = par;
- if (refork != 0)
- par.fork();
- }
- }
- else if (par.compareAndSetPendingCount(b, b|state))
- break outer; // sib not ready
- }
- }
- }
- }
- private static final long serialVersionUID = -586947823794232033L;
- }
-
- static final class IntCumulateTask extends CountedCompleter<Void> {
- final int[] array;
- final IntBinaryOperator function;
- IntCumulateTask left, right;
- int in, out;
- final int lo, hi, origin, fence, threshold;
-
- /** Root task constructor */
- public IntCumulateTask(IntCumulateTask parent,
- IntBinaryOperator function,
- int[] array, int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.lo = this.origin = lo; this.hi = this.fence = hi;
- int p;
- this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
- }
-
- /** Subtask constructor */
- IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function,
- int[] array, int origin, int fence, int threshold,
- int lo, int hi) {
- super(parent);
- this.function = function; this.array = array;
- this.origin = origin; this.fence = fence;
- this.threshold = threshold;
- this.lo = lo; this.hi = hi;
- }
-
- public final void compute() {
- final IntBinaryOperator fn;
- final int[] a;
- if ((fn = this.function) == null || (a = this.array) == null)
- throw new NullPointerException(); // hoist checks
- int th = threshold, org = origin, fnc = fence, l, h;
- IntCumulateTask t = this;
- outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
- if (h - l > th) {
- IntCumulateTask lt = t.left, rt = t.right, f;
- if (lt == null) { // first pass
- int mid = (l + h) >>> 1;
- f = rt = t.right =
- new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
- }
- else { // possibly refork
- int pin = t.in;
- lt.in = pin;
- f = t = null;
- if (rt != null) {
- int lout = lt.out;
- rt.in = (l == org ? lout :
- fn.applyAsInt(pin, lout));
- for (int c;;) {
- if (((c = rt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
- t = rt;
- break;
- }
- }
- }
- for (int c;;) {
- if (((c = lt.getPendingCount()) & CUMULATE) != 0)
- break;
- if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
- if (t != null)
- f = t;
- t = lt;
- break;
- }
- }
- if (t == null)
- break;
- }
- if (f != null)
- f.fork();
- }
- else {
- int state; // Transition to sum, cumulate, or both
- for (int b;;) {
- if (((b = t.getPendingCount()) & FINISHED) != 0)
- break outer; // already done
- state = ((b & CUMULATE) != 0 ? FINISHED :
- (l > org) ? SUMMED : (SUMMED|FINISHED));
- if (t.compareAndSetPendingCount(b, b|state))
- break;
- }
-
- int sum;
- if (state != SUMMED) {
- int first;
- if (l == org) { // leftmost; no in
- sum = a[org];
- first = org + 1;
- }
- else {
- sum = t.in;
- first = l;
- }
- for (int i = first; i < h; ++i) // cumulate
- a[i] = sum = fn.applyAsInt(sum, a[i]);
- }
- else if (h < fnc) { // skip rightmost
- sum = a[l];
- for (int i = l + 1; i < h; ++i) // sum only
- sum = fn.applyAsInt(sum, a[i]);
- }
- else
- sum = t.in;
- t.out = sum;
- for (IntCumulateTask par;;) { // propagate
- if ((par = (IntCumulateTask)t.getCompleter()) == null) {
- if ((state & FINISHED) != 0) // enable join
- t.quietlyComplete();
- break outer;
- }
- int b = par.getPendingCount();
- if ((b & state & FINISHED) != 0)
- t = par; // both done
- else if ((b & state & SUMMED) != 0) { // both summed
- int nextState; IntCumulateTask lt, rt;
- if ((lt = par.left) != null &&
- (rt = par.right) != null) {
- int lout = lt.out;
- par.out = (rt.hi == fnc ? lout :
- fn.applyAsInt(lout, rt.out));
- }
- int refork = (((b & CUMULATE) == 0 &&
- par.lo == org) ? CUMULATE : 0);
- if ((nextState = b|state|refork) == b ||
- par.compareAndSetPendingCount(b, nextState)) {
- state = SUMMED; // drop finished
- t = par;
- if (refork != 0)
- par.fork();
- }
- }
- else if (par.compareAndSetPendingCount(b, b|state))
- break outer; // sib not ready
- }
- }
- }
- }
- private static final long serialVersionUID = 3731755594596840961L;
- }
-}
diff --git a/ojluni/src/main/java/java/util/Deque.java b/ojluni/src/main/java/java/util/Deque.java
index 9fec73b..f230677 100644
--- a/ojluni/src/main/java/java/util/Deque.java
+++ b/ojluni/src/main/java/java/util/Deque.java
@@ -59,6 +59,7 @@
* <p>The twelve methods described above are summarized in the
* following table:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of Deque methods</caption>
* <tr>
@@ -102,6 +103,7 @@
* inherited from the {@code Queue} interface are precisely equivalent to
* {@code Deque} methods as indicated in the following table:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Comparison of Queue and Deque methods</caption>
* <tr>
@@ -140,6 +142,7 @@
* beginning of the deque. Stack methods are precisely equivalent to
* {@code Deque} methods as indicated in the table below:
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Comparison of Stack and Deque methods</caption>
* <tr>
@@ -187,7 +190,7 @@
* @author Doug Lea
* @author Josh Bloch
* @since 1.6
- * @param <E> the type of elements held in this deque
+ * @param <E> the type of elements held in this collection
*/
public interface Deque<E> extends Queue<E> {
/**
@@ -343,18 +346,17 @@
* Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the first element {@code e} such that
- * {@code Objects.equals(o, e)} (if such an element exists).
+ * <tt>(o==null ? e==null : o.equals(e))</tt>
+ * (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @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="Collection.html#optional-restrictions">optional</a>)
+ * is incompatible with this deque (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * deque does not permit null elements (optional)
*/
boolean removeFirstOccurrence(Object o);
@@ -362,18 +364,17 @@
* Removes the last occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the last element {@code e} such that
- * {@code Objects.equals(o, e)} (if such an element exists).
+ * <tt>(o==null ? e==null : o.equals(e))</tt>
+ * (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @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="Collection.html#optional-restrictions">optional</a>)
+ * is incompatible with this deque (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * deque does not permit null elements (optional)
*/
boolean removeLastOccurrence(Object o);
@@ -518,7 +519,8 @@
* Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the first element {@code e} such that
- * {@code Objects.equals(o, e)} (if such an element exists).
+ * <tt>(o==null ? e==null : o.equals(e))</tt>
+ * (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
@@ -527,27 +529,24 @@
* @param o element to be removed from this deque, if present
* @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="Collection.html#optional-restrictions">optional</a>)
+ * is incompatible with this deque (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * deque does not permit null elements (optional)
*/
boolean remove(Object o);
/**
* Returns {@code true} if this deque contains the specified element.
* More formally, returns {@code true} if and only if this deque contains
- * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+ * at least one element {@code e} such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this deque is to be tested
* @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="Collection.html#optional-restrictions">optional</a>)
+ * @throws ClassCastException if the type of the specified element
+ * is incompatible with this deque (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * deque does not permit null elements (optional)
*/
boolean contains(Object o);
@@ -556,7 +555,7 @@
*
* @return the number of elements in this deque
*/
- int size();
+ public int size();
/**
* Returns an iterator over the elements in this deque in proper sequence.
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
old mode 100644
new mode 100755
index 74ba701..f59b5a9
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2006, 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,43 +25,40 @@
package java.util;
+
+import java.io.Serializable;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
-import java.io.Serializable;
-// BEGIN android-note
-// removed link to collections framework docs
-// removed java 9 methods
-// END android-note
/**
* An object that maps keys to values. A map cannot contain duplicate keys;
* each key can map to at most one value.
*
- * <p>This interface takes the place of the {@code Dictionary} class, which
+ * <p>This interface takes the place of the <tt>Dictionary</tt> class, which
* was a totally abstract class rather than an interface.
*
- * <p>The {@code Map} interface provides three <i>collection views</i>, which
+ * <p>The <tt>Map</tt> interface provides three <i>collection views</i>, which
* allow a map's contents to be viewed as a set of keys, collection of values,
* or set of key-value mappings. The <i>order</i> of a map is defined as
* the order in which the iterators on the map's collection views return their
- * elements. Some map implementations, like the {@code TreeMap} class, make
- * specific guarantees as to their order; others, like the {@code HashMap}
+ * elements. Some map implementations, like the <tt>TreeMap</tt> class, make
+ * specific guarantees as to their order; others, like the <tt>HashMap</tt>
* class, do not.
*
* <p>Note: great care must be exercised if mutable objects are used as map
* keys. The behavior of a map is not specified if the value of an object is
- * changed in a manner that affects {@code equals} comparisons while the
+ * changed in a manner that affects <tt>equals</tt> comparisons while the
* object is a key in the map. A special case of this prohibition is that it
* is not permissible for a map to contain itself as a key. While it is
* permissible for a map to contain itself as a value, extreme caution is
- * advised: the {@code equals} and {@code hashCode} methods are no longer
+ * advised: the <tt>equals</tt> and <tt>hashCode</tt> methods are no longer
* well defined on such a map.
*
* <p>All general-purpose map implementation classes should provide two
* "standard" constructors: a void (no arguments) constructor which creates an
- * empty map, and a constructor with a single argument of type {@code Map},
+ * empty map, and a constructor with a single argument of type <tt>Map</tt>,
* which creates a new map with the same key-value mappings as its argument.
* In effect, the latter constructor allows the user to copy any map,
* producing an equivalent map of the desired class. There is no way to
@@ -70,9 +67,9 @@
*
* <p>The "destructive" methods contained in this interface, that is, the
* methods that modify the map on which they operate, are specified to throw
- * {@code UnsupportedOperationException} if this map does not support the
+ * <tt>UnsupportedOperationException</tt> if this map does not support the
* operation. If this is the case, these methods may, but are not required
- * to, throw an {@code UnsupportedOperationException} if the invocation would
+ * to, throw an <tt>UnsupportedOperationException</tt> if the invocation would
* have no effect on the map. For example, invoking the {@link #putAll(Map)}
* method on an unmodifiable map may, but is not required to, throw the
* exception if the map whose mappings are to be "superimposed" is empty.
@@ -81,7 +78,7 @@
* may contain. For example, some implementations prohibit null keys and
* values, and some have restrictions on the types of their keys. Attempting
* to insert an ineligible key or value throws an unchecked exception,
- * typically {@code NullPointerException} or {@code ClassCastException}.
+ * typically <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.
* Attempting to query the presence of an ineligible key or value may throw an
* exception, or it may simply return false; some implementations will exhibit
* the former behavior and some will exhibit the latter. More generally,
@@ -91,16 +88,20 @@
* Such exceptions are marked as "optional" in the specification for this
* interface.
*
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
* <p>Many methods in Collections Framework interfaces are defined
* in terms of the {@link Object#equals(Object) equals} method. For
* example, the specification for the {@link #containsKey(Object)
- * containsKey(Object key)} method says: "returns {@code true} if and
- * only if this map contains a mapping for a key {@code k} such that
- * {@code (key==null ? k==null : key.equals(k))}." This specification should
- * <i>not</i> be construed to imply that invoking {@code Map.containsKey}
- * with a non-null argument {@code key} will cause {@code key.equals(k)} to
- * be invoked for any key {@code k}. Implementations are free to
- * implement optimizations whereby the {@code equals} invocation is avoided,
+ * containsKey(Object key)} method says: "returns <tt>true</tt> if and
+ * only if this map contains a mapping for a key <tt>k</tt> such that
+ * <tt>(key==null ? k==null : key.equals(k))</tt>." This specification should
+ * <i>not</i> be construed to imply that invoking <tt>Map.containsKey</tt>
+ * with a non-null argument <tt>key</tt> will cause <tt>key.equals(k)</tt> to
+ * be invoked for any key <tt>k</tt>. Implementations are free to
+ * implement optimizations whereby the <tt>equals</tt> invocation is avoided,
* for example, by first comparing the hash codes of the two keys. (The
* {@link Object#hashCode()} specification guarantees that two objects with
* unequal hash codes cannot be equal.) More generally, implementations of
@@ -108,13 +109,6 @@
* the specified behavior of underlying {@link Object} methods wherever the
* implementor deems it appropriate.
*
- * <p>Some map operations which perform recursive traversal of the map may fail
- * with an exception for self-referential instances where the map directly or
- * indirectly contains itself. This includes the {@code clone()},
- * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
- * Implementations may optionally handle the self-referential scenario, however
- * most current implementations do not do so.
- *
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
*
@@ -127,34 +121,34 @@
* @see Set
* @since 1.2
*/
-public interface Map<K, V> {
+public interface Map<K,V> {
// Query Operations
/**
* Returns the number of key-value mappings in this map. If the
- * map contains more than {@code Integer.MAX_VALUE} elements, returns
- * {@code Integer.MAX_VALUE}.
+ * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
+ * <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of key-value mappings in this map
*/
int size();
/**
- * Returns {@code true} if this map contains no key-value mappings.
+ * Returns <tt>true</tt> if this map contains no key-value mappings.
*
- * @return {@code true} if this map contains no key-value mappings
+ * @return <tt>true</tt> if this map contains no key-value mappings
*/
boolean isEmpty();
/**
- * Returns {@code true} if this map contains a mapping for the specified
- * key. More formally, returns {@code true} if and only if
- * this map contains a mapping for a key {@code k} such that
- * {@code Objects.equals(key, k)}. (There can be
+ * Returns <tt>true</tt> if this map contains a mapping for the specified
+ * key. More formally, returns <tt>true</tt> if and only if
+ * this map contains a mapping for a key <tt>k</tt> such that
+ * <tt>(key==null ? k==null : key.equals(k))</tt>. (There can be
* at most one such mapping.)
*
* @param key key whose presence in this map is to be tested
- * @return {@code true} if this map contains a mapping for the specified
+ * @return <tt>true</tt> if this map contains a mapping for the specified
* key
* @throws ClassCastException if the key is of an inappropriate type for
* this map
@@ -166,15 +160,15 @@
boolean containsKey(Object key);
/**
- * Returns {@code true} if this map maps one or more keys to the
- * specified value. More formally, returns {@code true} if and only if
- * this map contains at least one mapping to a value {@code v} such that
- * {@code Objects.equals(value, v)}. This operation
+ * Returns <tt>true</tt> if this map maps one or more keys to the
+ * specified value. More formally, returns <tt>true</tt> if and only if
+ * this map contains at least one mapping to a value <tt>v</tt> such that
+ * <tt>(value==null ? v==null : value.equals(v))</tt>. This operation
* will probably require time linear in the map size for most
- * implementations of the {@code Map} interface.
+ * implementations of the <tt>Map</tt> interface.
*
* @param value value whose presence in this map is to be tested
- * @return {@code true} if this map maps one or more keys to the
+ * @return <tt>true</tt> if this map maps one or more keys to the
* specified value
* @throws ClassCastException if the value is of an inappropriate type for
* this map
@@ -190,9 +184,8 @@
* or {@code null} if this map contains no mapping for the key.
*
* <p>More formally, if this map contains a mapping from a key
- * {@code k} to a value {@code v} such that
- * {@code Objects.equals(key, k)},
- * then this method returns {@code v}; otherwise
+ * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+ * key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
*
* <p>If this map permits null values, then a return value of
@@ -219,18 +212,18 @@
* Associates the specified value with the specified key in this map
* (optional operation). If the map previously contained a mapping for
* the key, the old value is replaced by the specified value. (A map
- * {@code m} is said to contain a mapping for a key {@code k} if and only
+ * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only
* if {@link #containsKey(Object) m.containsKey(k)} would return
- * {@code true}.)
+ * <tt>true</tt>.)
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
- * @return the previous value associated with {@code key}, or
- * {@code null} if there was no mapping for {@code key}.
- * (A {@code null} return can also indicate that the map
- * previously associated {@code null} with {@code key},
- * if the implementation supports {@code null} values.)
- * @throws UnsupportedOperationException if the {@code put} operation
+ * @return the previous value associated with <tt>key</tt>, or
+ * <tt>null</tt> if there was no mapping for <tt>key</tt>.
+ * (A <tt>null</tt> return can also indicate that the map
+ * previously associated <tt>null</tt> with <tt>key</tt>,
+ * if the implementation supports <tt>null</tt> values.)
+ * @throws UnsupportedOperationException if the <tt>put</tt> operation
* is not supported by this map
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
@@ -244,25 +237,25 @@
/**
* Removes the mapping for a key from this map if it is present
* (optional operation). More formally, if this map contains a mapping
- * from key {@code k} to value {@code v} such that
- * {@code Objects.equals(key, k)}, that mapping
+ * from key <tt>k</tt> to value <tt>v</tt> such that
+ * <code>(key==null ? k==null : key.equals(k))</code>, that mapping
* is removed. (The map can contain at most one such mapping.)
*
* <p>Returns the value to which this map previously associated the key,
- * or {@code null} if the map contained no mapping for the key.
+ * or <tt>null</tt> if the map contained no mapping for the key.
*
* <p>If this map permits null values, then a return value of
- * {@code null} does not <i>necessarily</i> indicate that the map
+ * <tt>null</tt> does not <i>necessarily</i> indicate that the map
* contained no mapping for the key; it's also possible that the map
- * explicitly mapped the key to {@code null}.
+ * explicitly mapped the key to <tt>null</tt>.
*
* <p>The map will not contain a mapping for the specified key once the
* call returns.
*
* @param key key whose mapping is to be removed from the map
- * @return the previous value associated with {@code key}, or
- * {@code null} if there was no mapping for {@code key}.
- * @throws UnsupportedOperationException if the {@code remove} operation
+ * @return the previous value associated with <tt>key</tt>, or
+ * <tt>null</tt> if there was no mapping for <tt>key</tt>.
+ * @throws UnsupportedOperationException if the <tt>remove</tt> operation
* is not supported by this map
* @throws ClassCastException if the key is of an inappropriate type for
* this map
@@ -280,12 +273,12 @@
* Copies all of the mappings from the specified map to this map
* (optional operation). The effect of this call is equivalent to that
* of calling {@link #put(Object,Object) put(k, v)} on this map once
- * for each mapping from key {@code k} to value {@code v} in the
+ * for each mapping from key <tt>k</tt> to value <tt>v</tt> in the
* specified map. The behavior of this operation is undefined if the
* specified map is modified while the operation is in progress.
*
* @param m mappings to be stored in this map
- * @throws UnsupportedOperationException if the {@code putAll} operation
+ * @throws UnsupportedOperationException if the <tt>putAll</tt> operation
* is not supported by this map
* @throws ClassCastException if the class of a key or value in the
* specified map prevents it from being stored in this map
@@ -301,7 +294,7 @@
* Removes all of the mappings from this map (optional operation).
* The map will be empty after this call returns.
*
- * @throws UnsupportedOperationException if the {@code clear} operation
+ * @throws UnsupportedOperationException if the <tt>clear</tt> operation
* is not supported by this map
*/
void clear();
@@ -314,12 +307,12 @@
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
- * the iterator's own {@code remove} operation), the results of
+ * the iterator's own <tt>remove</tt> operation), the results of
* the iteration are undefined. The set supports element removal,
* which removes the corresponding mapping from the map, via the
- * {@code Iterator.remove}, {@code Set.remove},
- * {@code removeAll}, {@code retainAll}, and {@code clear}
- * operations. It does not support the {@code add} or {@code addAll}
+ * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+ * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
* operations.
*
* @return a set view of the keys contained in this map
@@ -331,13 +324,13 @@
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. If the map is
* modified while an iteration over the collection is in progress
- * (except through the iterator's own {@code remove} operation),
+ * (except through the iterator's own <tt>remove</tt> operation),
* the results of the iteration are undefined. The collection
* supports element removal, which removes the corresponding
- * mapping from the map, via the {@code Iterator.remove},
- * {@code Collection.remove}, {@code removeAll},
- * {@code retainAll} and {@code clear} operations. It does not
- * support the {@code add} or {@code addAll} operations.
+ * mapping from the map, via the <tt>Iterator.remove</tt>,
+ * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+ * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
+ * support the <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return a collection view of the values contained in this map
*/
@@ -348,33 +341,33 @@
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
- * the iterator's own {@code remove} operation, or through the
- * {@code setValue} operation on a map entry returned by the
+ * the iterator's own <tt>remove</tt> operation, or through the
+ * <tt>setValue</tt> operation on a map entry returned by the
* iterator) the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
- * mapping from the map, via the {@code Iterator.remove},
- * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
- * {@code clear} operations. It does not support the
- * {@code add} or {@code addAll} operations.
+ * mapping from the map, via the <tt>Iterator.remove</tt>,
+ * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+ * <tt>clear</tt> operations. It does not support the
+ * <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return a set view of the mappings contained in this map
*/
Set<Map.Entry<K, V>> entrySet();
/**
- * A map entry (key-value pair). The {@code Map.entrySet} method returns
+ * A map entry (key-value pair). The <tt>Map.entrySet</tt> method returns
* a collection-view of the map, whose elements are of this class. The
* <i>only</i> way to obtain a reference to a map entry is from the
- * iterator of this collection-view. These {@code Map.Entry} objects are
+ * iterator of this collection-view. These <tt>Map.Entry</tt> objects are
* valid <i>only</i> for the duration of the iteration; more formally,
* the behavior of a map entry is undefined if the backing map has been
* modified after the entry was returned by the iterator, except through
- * the {@code setValue} operation on the map entry.
+ * the <tt>setValue</tt> operation on the map entry.
*
* @see Map#entrySet()
* @since 1.2
*/
- interface Entry<K, V> {
+ interface Entry<K,V> {
/**
* Returns the key corresponding to this entry.
*
@@ -388,7 +381,7 @@
/**
* Returns the value corresponding to this entry. If the mapping
* has been removed from the backing map (by the iterator's
- * {@code remove} operation), the results of this call are undefined.
+ * <tt>remove</tt> operation), the results of this call are undefined.
*
* @return the value corresponding to this entry
* @throws IllegalStateException implementations may, but are not
@@ -401,11 +394,11 @@
* Replaces the value corresponding to this entry with the specified
* value (optional operation). (Writes through to the map.) The
* behavior of this call is undefined if the mapping has already been
- * removed from the map (by the iterator's {@code remove} operation).
+ * removed from the map (by the iterator's <tt>remove</tt> operation).
*
* @param value new value to be stored in this entry
* @return old value corresponding to the entry
- * @throws UnsupportedOperationException if the {@code put} operation
+ * @throws UnsupportedOperationException if the <tt>put</tt> operation
* is not supported by the backing map
* @throws ClassCastException if the class of the specified value
* prevents it from being stored in the backing map
@@ -421,34 +414,34 @@
/**
* Compares the specified object with this entry for equality.
- * Returns {@code true} if the given object is also a map entry and
+ * Returns <tt>true</tt> if the given object is also a map entry and
* the two entries represent the same mapping. More formally, two
- * entries {@code e1} and {@code e2} represent the same mapping
+ * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
* if<pre>
* (e1.getKey()==null ?
* e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
* (e1.getValue()==null ?
* e2.getValue()==null : e1.getValue().equals(e2.getValue()))
* </pre>
- * This ensures that the {@code equals} method works properly across
- * different implementations of the {@code Map.Entry} interface.
+ * This ensures that the <tt>equals</tt> method works properly across
+ * different implementations of the <tt>Map.Entry</tt> interface.
*
* @param o object to be compared for equality with this map entry
- * @return {@code true} if the specified object is equal to this map
+ * @return <tt>true</tt> if the specified object is equal to this map
* entry
*/
boolean equals(Object o);
/**
* Returns the hash code value for this map entry. The hash code
- * of a map entry {@code e} is defined to be: <pre>
+ * of a map entry <tt>e</tt> is defined to be: <pre>
* (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
* (e.getValue()==null ? 0 : e.getValue().hashCode())
* </pre>
- * This ensures that {@code e1.equals(e2)} implies that
- * {@code e1.hashCode()==e2.hashCode()} for any two Entries
- * {@code e1} and {@code e2}, as required by the general
- * contract of {@code Object.hashCode}.
+ * This ensures that <tt>e1.equals(e2)</tt> implies that
+ * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
+ * <tt>e1</tt> and <tt>e2</tt>, as required by the general
+ * contract of <tt>Object.hashCode</tt>.
*
* @return the hash code value for this map entry
* @see Object#hashCode()
@@ -469,29 +462,12 @@
* @see Comparable
* @since 1.8
*/
- public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
+ public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
/**
- * Returns a comparator that compares {@link Map.Entry} in natural order on value.
- *
- * <p>The returned comparator is serializable and throws {@link
- * NullPointerException} when comparing an entry with null values.
- *
- * @param <K> the type of the map keys
- * @param <V> the {@link Comparable} type of the map values
- * @return a comparator that compares {@link Map.Entry} in natural order on value.
- * @see Comparable
- * @since 1.8
- */
- public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
- return (Comparator<Map.Entry<K, V>> & Serializable)
- (c1, c2) -> c1.getValue().compareTo(c2.getValue());
- }
-
- /**
* Returns a comparator that compares {@link Map.Entry} by key using the given
* {@link Comparator}.
*
@@ -509,49 +485,30 @@
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
-
- /**
- * Returns a comparator that compares {@link Map.Entry} by value using the given
- * {@link Comparator}.
- *
- * <p>The returned comparator is serializable if the specified comparator
- * is also serializable.
- *
- * @param <K> the type of the map keys
- * @param <V> the type of the map values
- * @param cmp the value {@link Comparator}
- * @return a comparator that compares {@link Map.Entry} by the value.
- * @since 1.8
- */
- public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
- Objects.requireNonNull(cmp);
- return (Comparator<Map.Entry<K, V>> & Serializable)
- (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
- }
}
// Comparison and hashing
/**
* Compares the specified object with this map for equality. Returns
- * {@code true} if the given object is also a map and the two maps
- * represent the same mappings. More formally, two maps {@code m1} and
- * {@code m2} represent the same mappings if
- * {@code m1.entrySet().equals(m2.entrySet())}. This ensures that the
- * {@code equals} method works properly across different implementations
- * of the {@code Map} interface.
+ * <tt>true</tt> if the given object is also a map and the two maps
+ * represent the same mappings. More formally, two maps <tt>m1</tt> and
+ * <tt>m2</tt> represent the same mappings if
+ * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This ensures that the
+ * <tt>equals</tt> method works properly across different implementations
+ * of the <tt>Map</tt> interface.
*
* @param o object to be compared for equality with this map
- * @return {@code true} if the specified object is equal to this map
+ * @return <tt>true</tt> if the specified object is equal to this map
*/
boolean equals(Object o);
/**
* Returns the hash code value for this map. The hash code of a map is
* defined to be the sum of the hash codes of each entry in the map's
- * {@code entrySet()} view. This ensures that {@code m1.equals(m2)}
- * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
- * {@code m1} and {@code m2}, as required by the general contract of
+ * <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>
+ * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
+ * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this map
@@ -561,37 +518,6 @@
*/
int hashCode();
- // Defaultable methods
-
- /**
- * Returns the value to which the specified key is mapped, or
- * {@code defaultValue} if this map contains no mapping for the key.
- *
- * @implSpec
- * The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param key the key whose associated value is to be returned
- * @param defaultValue the default mapping of the key
- * @return the value to which the specified key is mapped, or
- * {@code defaultValue} if this map contains no mapping for the key
- * @throws ClassCastException if the key is of an inappropriate type for
- * this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws NullPointerException if the specified key is null and this map
- * does not permit null keys
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default V getOrDefault(Object key, V defaultValue) {
- V v;
- return (((v = get(key)) != null) || containsKey(key))
- ? v
- : defaultValue;
- }
-
/**
* Performs the given action for each entry in this map until all entries
* have been processed or the action throws an exception. Unless
@@ -625,625 +551,11 @@
try {
k = entry.getKey();
v = entry.getValue();
- } catch (IllegalStateException ise) {
+ } catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
-
- /**
- * Replaces each entry's value with the result of invoking the given
- * function on that entry until all entries have been processed or the
- * function throws an exception. Exceptions thrown by the function are
- * relayed to the caller.
- *
- * @implSpec
- * <p>The default implementation is equivalent to, for this {@code map}:
- * <pre> {@code
- * for (Map.Entry<K, V> entry : map.entrySet())
- * entry.setValue(function.apply(entry.getKey(), entry.getValue()));
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param function the function to apply to each entry
- * @throws UnsupportedOperationException if the {@code set} operation
- * is not supported by this map's entry set iterator.
- * @throws ClassCastException if the class of a replacement value
- * prevents it from being stored in this map
- * @throws NullPointerException if the specified function is null, or the
- * specified replacement value is null, and this map does not permit null
- * values
- * @throws ClassCastException if a replacement value is of an inappropriate
- * type for this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws NullPointerException if function or a replacement value is null,
- * and this map does not permit null keys or values
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of a replacement value
- * prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ConcurrentModificationException if an entry is found to be
- * removed during iteration
- * @since 1.8
- */
- default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
- Objects.requireNonNull(function);
- for (Map.Entry<K, V> entry : entrySet()) {
- K k;
- V v;
- try {
- k = entry.getKey();
- v = entry.getValue();
- } catch (IllegalStateException ise) {
- // this usually means the entry is no longer in the map.
- throw new ConcurrentModificationException(ise);
- }
-
- // ise thrown from function is not a cme.
- v = function.apply(k, v);
-
- try {
- entry.setValue(v);
- } catch (IllegalStateException ise) {
- // this usually means the entry is no longer in the map.
- throw new ConcurrentModificationException(ise);
- }
- }
- }
-
- /**
- * If the specified key is not already associated with a value (or is mapped
- * to {@code null}) associates it with the given value and returns
- * {@code null}, else returns the current value.
- *
- * @implSpec
- * The default implementation is equivalent to, for this {@code
- * map}:
- *
- * <pre> {@code
- * V v = map.get(key);
- * if (v == null)
- * v = map.put(key, value);
- *
- * return v;
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param key key with which the specified value is to be associated
- * @param value value to be associated with the specified key
- * @return the previous value associated with the specified key, or
- * {@code null} if there was no mapping for the key.
- * (A {@code null} return can also indicate that the map
- * previously associated {@code null} with the key,
- * if the implementation supports null values.)
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the key or value is of an inappropriate
- * type for this map
- * (<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="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default V putIfAbsent(K key, V value) {
- V v = get(key);
- if (v == null) {
- v = put(key, value);
- }
-
- return v;
- }
-
- /**
- * Removes the entry for the specified key only if it is currently
- * mapped to the specified value.
- *
- * @implSpec
- * The default implementation is equivalent to, for this {@code map}:
- *
- * <pre> {@code
- * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
- * map.remove(key);
- * return true;
- * } else
- * return false;
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param key key with which the specified value is associated
- * @param value value expected to be associated with the specified key
- * @return {@code true} if the value was removed
- * @throws UnsupportedOperationException if the {@code remove} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the key or value is of an inappropriate
- * type for this map
- * (<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="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default boolean remove(Object key, Object value) {
- Object curValue = get(key);
- if (!Objects.equals(curValue, value) ||
- (curValue == null && !containsKey(key))) {
- return false;
- }
- remove(key);
- return true;
- }
-
- /**
- * Replaces the entry for the specified key only if currently
- * mapped to the specified value.
- *
- * @implSpec
- * The default implementation is equivalent to, for this {@code map}:
- *
- * <pre> {@code
- * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
- * map.put(key, newValue);
- * return true;
- * } else
- * return false;
- * }</pre>
- *
- * The default implementation does not throw NullPointerException
- * for maps that do not support null values if oldValue is null unless
- * newValue is also null.
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param key key with which the specified value is associated
- * @param oldValue value expected to be associated with the specified key
- * @param newValue value to be associated with the specified key
- * @return {@code true} if the value was replaced
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of a specified key or value
- * prevents it from being stored in this map
- * @throws NullPointerException if a specified key or newValue is null,
- * and this map does not permit null keys or values
- * @throws NullPointerException if oldValue is null and this map does not
- * permit null values
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of a specified key
- * or value prevents it from being stored in this map
- * @since 1.8
- */
- default boolean replace(K key, V oldValue, V newValue) {
- Object curValue = get(key);
- if (!Objects.equals(curValue, oldValue) ||
- (curValue == null && !containsKey(key))) {
- return false;
- }
- put(key, newValue);
- return true;
- }
-
- /**
- * Replaces the entry for the specified key only if it is
- * currently mapped to some value.
- *
- * @implSpec
- * The default implementation is equivalent to, for this {@code map}:
- *
- * <pre> {@code
- * if (map.containsKey(key)) {
- * return map.put(key, value);
- * } else
- * return null;
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties.
- *
- * @param key key with which the specified value is associated
- * @param value value to be associated with the specified key
- * @return the previous value associated with the specified key, or
- * {@code null} if there was no mapping for the key.
- * (A {@code null} return can also indicate that the map
- * previously associated {@code null} with the key,
- * if the implementation supports null values.)
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of the specified key or value
- * prevents it from being stored in this map
- * (<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
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * @since 1.8
- */
- default V replace(K key, V value) {
- V curValue;
- if (((curValue = get(key)) != null) || containsKey(key)) {
- curValue = put(key, value);
- }
- return curValue;
- }
-
- /**
- * If the specified key is not already associated with a value (or is mapped
- * to {@code null}), attempts to compute its value using the given mapping
- * function and enters it into this map unless {@code null}.
- *
- * <p>If the mapping function returns {@code null}, no mapping is recorded.
- * If the mapping function itself throws an (unchecked) exception, the
- * exception is rethrown, and no mapping is recorded. The most
- * common usage is to construct a new object serving as an initial
- * mapped value or memoized result, as in:
- *
- * <pre> {@code
- * map.computeIfAbsent(key, k -> new Value(f(k)));
- * }</pre>
- *
- * <p>Or to implement a multi-value map, {@code Map<K,Collection<V>>},
- * supporting multiple values per key:
- *
- * <pre> {@code
- * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
- * }</pre>
- *
- * <p>The mapping function should not modify this map during computation.
- *
- * @implSpec
- * The default implementation is equivalent to the following steps for this
- * {@code map}, then returning the current value or {@code null} if now
- * absent:
- *
- * <pre> {@code
- * if (map.get(key) == null) {
- * V newValue = mappingFunction.apply(key);
- * if (newValue != null)
- * map.put(key, newValue);
- * }
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about detecting if the
- * mapping function modifies this map during computation and, if
- * appropriate, reporting an error. Non-concurrent implementations should
- * override this method and, on a best-effort basis, throw a
- * {@code ConcurrentModificationException} if it is detected that the
- * mapping function modifies this map during computation. Concurrent
- * implementations should override this method and, on a best-effort basis,
- * throw an {@code IllegalStateException} if it is detected that the
- * mapping function modifies this map during computation and as a result
- * computation would never complete.
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties. In particular, all implementations of
- * subinterface {@link java.util.concurrent.ConcurrentMap} must document
- * whether the mapping function is applied once atomically only if the value
- * is not present.
- *
- * @param key key with which the specified value is to be associated
- * @param mappingFunction the mapping function to compute a value
- * @return the current (existing or computed) value associated with
- * the specified key, or null if the computed value is null
- * @throws NullPointerException if the specified key is null and
- * this map does not support null keys, or the mappingFunction
- * is null
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of the specified key or value
- * prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default V computeIfAbsent(K key,
- Function<? super K, ? extends V> mappingFunction) {
- Objects.requireNonNull(mappingFunction);
- V v;
- if ((v = get(key)) == null) {
- V newValue;
- if ((newValue = mappingFunction.apply(key)) != null) {
- put(key, newValue);
- return newValue;
- }
- }
-
- return v;
- }
-
- /**
- * If the value for the specified key is present and non-null, attempts to
- * compute a new mapping given the key and its current mapped value.
- *
- * <p>If the remapping function returns {@code null}, the mapping is removed.
- * If the remapping function itself throws an (unchecked) exception, the
- * exception is rethrown, and the current mapping is left unchanged.
- *
- * <p>The remapping function should not modify this map during computation.
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}, then returning the current value or
- * {@code null} if now absent:
- *
- * <pre> {@code
- * if (map.get(key) != null) {
- * V oldValue = map.get(key);
- * V newValue = remappingFunction.apply(key, oldValue);
- * if (newValue != null)
- * map.put(key, newValue);
- * else
- * map.remove(key);
- * }
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about detecting if the
- * remapping function modifies this map during computation and, if
- * appropriate, reporting an error. Non-concurrent implementations should
- * override this method and, on a best-effort basis, throw a
- * {@code ConcurrentModificationException} if it is detected that the
- * remapping function modifies this map during computation. Concurrent
- * implementations should override this method and, on a best-effort basis,
- * throw an {@code IllegalStateException} if it is detected that the
- * remapping function modifies this map during computation and as a result
- * computation would never complete.
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties. In particular, all implementations of
- * subinterface {@link java.util.concurrent.ConcurrentMap} must document
- * whether the remapping function is applied once atomically only if the
- * value is not present.
- *
- * @param key key with which the specified value is to be associated
- * @param remappingFunction the remapping function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key is null and
- * this map does not support null keys, or the
- * remappingFunction is null
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of the specified key or value
- * prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default V computeIfPresent(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- Objects.requireNonNull(remappingFunction);
- V oldValue;
- if ((oldValue = get(key)) != null) {
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != null) {
- put(key, newValue);
- return newValue;
- } else {
- remove(key);
- return null;
- }
- } else {
- return null;
- }
- }
-
- /**
- * Attempts to compute a mapping for the specified key and its current
- * mapped value (or {@code null} if there is no current mapping). For
- * example, to either create or append a {@code String} msg to a value
- * mapping:
- *
- * <pre> {@code
- * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
- * (Method {@link #merge merge()} is often simpler to use for such purposes.)
- *
- * <p>If the remapping function returns {@code null}, the mapping is removed
- * (or remains absent if initially absent). If the remapping function
- * itself throws an (unchecked) exception, the exception is rethrown, and
- * the current mapping is left unchanged.
- *
- * <p>The remapping function should not modify this map during computation.
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}, then returning the current value or
- * {@code null} if absent:
- *
- * <pre> {@code
- * V oldValue = map.get(key);
- * V newValue = remappingFunction.apply(key, oldValue);
- * if (oldValue != null) {
- * if (newValue != null)
- * map.put(key, newValue);
- * else
- * map.remove(key);
- * } else {
- * if (newValue != null)
- * map.put(key, newValue);
- * else
- * return null;
- * }
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about detecting if the
- * remapping function modifies this map during computation and, if
- * appropriate, reporting an error. Non-concurrent implementations should
- * override this method and, on a best-effort basis, throw a
- * {@code ConcurrentModificationException} if it is detected that the
- * remapping function modifies this map during computation. Concurrent
- * implementations should override this method and, on a best-effort basis,
- * throw an {@code IllegalStateException} if it is detected that the
- * remapping function modifies this map during computation and as a result
- * computation would never complete.
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties. In particular, all implementations of
- * subinterface {@link java.util.concurrent.ConcurrentMap} must document
- * whether the remapping function is applied once atomically only if the
- * value is not present.
- *
- * @param key key with which the specified value is to be associated
- * @param remappingFunction the remapping function to compute a value
- * @return the new value associated with the specified key, or null if none
- * @throws NullPointerException if the specified key is null and
- * this map does not support null keys, or the
- * remappingFunction is null
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of the specified key or value
- * prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @since 1.8
- */
- default V compute(K key,
- BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- Objects.requireNonNull(remappingFunction);
- V oldValue = get(key);
-
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue == null) {
- // delete mapping
- if (oldValue != null || containsKey(key)) {
- // something to remove
- remove(key);
- return null;
- } else {
- // nothing to do. Leave things as they were.
- return null;
- }
- } else {
- // add or replace old mapping
- put(key, newValue);
- return newValue;
- }
- }
-
- /**
- * If the specified key is not already associated with a value or is
- * associated with null, associates it with the given non-null value.
- * Otherwise, replaces the associated value with the results of the given
- * remapping function, or removes if the result is {@code null}. This
- * method may be of use when combining multiple mapped values for a key.
- * For example, to either create or append a {@code String msg} to a
- * value mapping:
- *
- * <pre> {@code
- * map.merge(key, msg, String::concat)
- * }</pre>
- *
- * <p>If the remapping function returns {@code null}, the mapping is removed.
- * If the remapping function itself throws an (unchecked) exception, the
- * exception is rethrown, and the current mapping is left unchanged.
- *
- * <p>The remapping function should not modify this map during computation.
- *
- * @implSpec
- * The default implementation is equivalent to performing the following
- * steps for this {@code map}, then returning the current value or
- * {@code null} if absent:
- *
- * <pre> {@code
- * V oldValue = map.get(key);
- * V newValue = (oldValue == null) ? value :
- * remappingFunction.apply(oldValue, value);
- * if (newValue == null)
- * map.remove(key);
- * else
- * map.put(key, newValue);
- * }</pre>
- *
- * <p>The default implementation makes no guarantees about detecting if the
- * remapping function modifies this map during computation and, if
- * appropriate, reporting an error. Non-concurrent implementations should
- * override this method and, on a best-effort basis, throw a
- * {@code ConcurrentModificationException} if it is detected that the
- * remapping function modifies this map during computation. Concurrent
- * implementations should override this method and, on a best-effort basis,
- * throw an {@code IllegalStateException} if it is detected that the
- * remapping function modifies this map during computation and as a result
- * computation would never complete.
- *
- * <p>The default implementation makes no guarantees about synchronization
- * or atomicity properties of this method. Any implementation providing
- * atomicity guarantees must override this method and document its
- * concurrency properties. In particular, all implementations of
- * subinterface {@link java.util.concurrent.ConcurrentMap} must document
- * whether the remapping function is applied once atomically only if the
- * value is not present.
- *
- * @param key key with which the resulting value is to be associated
- * @param value the non-null value to be merged with the existing value
- * associated with the key or, if no existing value or a null value
- * is associated with the key, to be associated with the key
- * @param remappingFunction the remapping function to recompute a value if
- * present
- * @return the new value associated with the specified key, or null if no
- * value is associated with the key
- * @throws UnsupportedOperationException if the {@code put} operation
- * is not supported by this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws ClassCastException if the class of the specified key or value
- * prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws IllegalArgumentException if some property of the specified key
- * or value prevents it from being stored in this map
- * (<a href="Collection.html#optional-restrictions">optional</a>)
- * @throws NullPointerException if the specified key is null and this map
- * does not support null keys or the value or remappingFunction is
- * null
- * @since 1.8
- */
- default V merge(K key, V value,
- BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
- Objects.requireNonNull(remappingFunction);
- Objects.requireNonNull(value);
- V oldValue = get(key);
- V newValue = (oldValue == null) ? value :
- remappingFunction.apply(oldValue, value);
- if (newValue == null) {
- remove(key);
- } else {
- put(key, newValue);
- }
- return newValue;
- }
}
diff --git a/ojluni/src/main/java/java/util/NavigableMap.java b/ojluni/src/main/java/java/util/NavigableMap.java
index fdbc0b5..b0d9453 100644
--- a/ojluni/src/main/java/java/util/NavigableMap.java
+++ b/ojluni/src/main/java/java/util/NavigableMap.java
@@ -41,32 +41,30 @@
/**
* A {@link SortedMap} extended with navigation methods returning the
* closest matches for given search targets. Methods
- * {@link #lowerEntry}, {@link #floorEntry}, {@link #ceilingEntry},
- * and {@link #higherEntry} return {@code Map.Entry} objects
+ * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry},
+ * and {@code higherEntry} return {@code Map.Entry} objects
* associated with keys respectively less than, less than or equal,
* greater than or equal, and greater than a given key, returning
* {@code null} if there is no such key. Similarly, methods
- * {@link #lowerKey}, {@link #floorKey}, {@link #ceilingKey}, and
- * {@link #higherKey} return only the associated keys. All of these
+ * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and
+ * {@code higherKey} return only the associated keys. All of these
* methods are designed for locating, not traversing entries.
*
* <p>A {@code NavigableMap} may be accessed and traversed in either
- * ascending or descending key order. The {@link #descendingMap}
+ * ascending or descending key order. The {@code descendingMap}
* method returns a view of the map with the senses of all relational
* and directional methods inverted. The performance of ascending
* operations and views is likely to be faster than that of descending
- * ones. Methods
- * {@link #subMap(Object, boolean, Object, boolean) subMap(K, boolean, K, boolean)},
- * {@link #headMap(Object, boolean) headMap(K, boolean)}, and
- * {@link #tailMap(Object, boolean) tailMap(K, boolean)}
- * differ from the like-named {@code SortedMap} methods in accepting
- * additional arguments describing whether lower and upper bounds are
- * inclusive versus exclusive. Submaps of any {@code NavigableMap}
- * must implement the {@code NavigableMap} interface.
+ * ones. Methods {@code subMap}, {@code headMap},
+ * and {@code tailMap} differ from the like-named {@code
+ * SortedMap} methods in accepting additional arguments describing
+ * whether lower and upper bounds are inclusive versus exclusive.
+ * Submaps of any {@code NavigableMap} must implement the {@code
+ * NavigableMap} interface.
*
- * <p>This interface additionally defines methods {@link #firstEntry},
- * {@link #pollFirstEntry}, {@link #lastEntry}, and
- * {@link #pollLastEntry} that return and/or remove the least and
+ * <p>This interface additionally defines methods {@code firstEntry},
+ * {@code pollFirstEntry}, {@code lastEntry}, and
+ * {@code pollLastEntry} that return and/or remove the least and
* greatest mappings, if any exist, else returning {@code null}.
*
* <p>Implementations of entry-returning methods are expected to
@@ -85,7 +83,7 @@
* implement {@code NavigableMap}, but extensions and implementations
* of this interface are encouraged to override these methods to return
* {@code NavigableMap}. Similarly,
- * {@link #keySet()} can be overridden to return {@link NavigableSet}.
+ * {@link #keySet()} can be overridden to return {@code NavigableSet}.
*
* @author Doug Lea
* @author Josh Bloch
@@ -299,7 +297,7 @@
* Returns a view of the portion of this map whose keys range from
* {@code fromKey} to {@code toKey}. If {@code fromKey} and
* {@code toKey} are equal, the returned map is empty unless
- * {@code fromInclusive} and {@code toInclusive} are both true. The
+ * {@code fromExclusive} and {@code toExclusive} are both true. The
* returned map is backed by this map, so changes in the returned map are
* reflected in this map, and vice-versa. The returned map supports all
* optional map operations that this map supports.
diff --git a/ojluni/src/main/java/java/util/NavigableSet.java b/ojluni/src/main/java/java/util/NavigableSet.java
index 412a07d..11a9bdb 100644
--- a/ojluni/src/main/java/java/util/NavigableSet.java
+++ b/ojluni/src/main/java/java/util/NavigableSet.java
@@ -32,36 +32,32 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
+package java.util;
+
// BEGIN android-note
// removed link to collections framework docs
// END android-note
-package java.util;
-
/**
* A {@link SortedSet} extended with navigation methods reporting
- * closest matches for given search targets. Methods {@link #lower},
- * {@link #floor}, {@link #ceiling}, and {@link #higher} return elements
+ * closest matches for given search targets. Methods {@code lower},
+ * {@code floor}, {@code ceiling}, and {@code higher} return elements
* respectively less than, less than or equal, greater than or equal,
* and greater than a given element, returning {@code null} if there
- * is no such element.
- *
- * <p>A {@code NavigableSet} may be accessed and traversed in either
- * ascending or descending order. The {@link #descendingSet} method
- * returns a view of the set with the senses of all relational and
- * directional methods inverted. The performance of ascending
- * operations and views is likely to be faster than that of descending
- * ones. This interface additionally defines methods {@link
- * #pollFirst} and {@link #pollLast} that return and remove the lowest
- * and highest element, if one exists, else returning {@code null}.
- * Methods
- * {@link #subSet(Object, boolean, Object, boolean) subSet(E, boolean, E, boolean)},
- * {@link #headSet(Object, boolean) headSet(E, boolean)}, and
- * {@link #tailSet(Object, boolean) tailSet(E, boolean)}
- * differ from the like-named {@code SortedSet} methods in accepting
- * additional arguments describing whether lower and upper bounds are
- * inclusive versus exclusive. Subsets of any {@code NavigableSet}
- * must implement the {@code NavigableSet} interface.
+ * is no such element. A {@code NavigableSet} may be accessed and
+ * traversed in either ascending or descending order. The {@code
+ * descendingSet} method returns a view of the set with the senses of
+ * all relational and directional methods inverted. The performance of
+ * ascending operations and views is likely to be faster than that of
+ * descending ones. This interface additionally defines methods
+ * {@code pollFirst} and {@code pollLast} that return and remove the
+ * lowest and highest element, if one exists, else returning {@code
+ * null}. Methods {@code subSet}, {@code headSet},
+ * and {@code tailSet} differ from the like-named {@code
+ * SortedSet} methods in accepting additional arguments describing
+ * whether lower and upper bounds are inclusive versus exclusive.
+ * Subsets of any {@code NavigableSet} must implement the {@code
+ * NavigableSet} interface.
*
* <p>The return values of navigation methods may be ambiguous in
* implementations that permit {@code null} elements. However, even
@@ -195,7 +191,7 @@
* Returns a view of the portion of this set whose elements range from
* {@code fromElement} to {@code toElement}. If {@code fromElement} and
* {@code toElement} are equal, the returned set is empty unless {@code
- * fromInclusive} and {@code toInclusive} are both true. The returned set
+ * fromExclusive} and {@code toExclusive} are both true. The returned set
* is backed by this set, so changes in the returned set are reflected in
* this set, and vice-versa. The returned set supports all optional set
* operations that this set supports.
diff --git a/ojluni/src/main/java/java/util/PriorityQueue.java b/ojluni/src/main/java/java/util/PriorityQueue.java
old mode 100644
new mode 100755
index 7c929bd..b42647e
--- a/ojluni/src/main/java/java/util/PriorityQueue.java
+++ b/ojluni/src/main/java/java/util/PriorityQueue.java
@@ -77,7 +77,7 @@
*
* @since 1.5
* @author Josh Bloch, Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
@@ -99,7 +99,7 @@
/**
* The number of elements in the priority queue.
*/
- int size;
+ private int size = 0;
/**
* The comparator, or null if priority queue uses elements'
@@ -111,7 +111,7 @@
* The number of times this priority queue has been
* <i>structurally modified</i>. See AbstractList for gory details.
*/
- transient int modCount; // non-private to simplify nested class access
+ transient int modCount = 0; // non-private to simplify nested class access
/**
* Creates a {@code PriorityQueue} with the default initial
@@ -258,8 +258,8 @@
a = Arrays.copyOf(a, a.length, Object[].class);
int len = a.length;
if (len == 1 || this.comparator != null)
- for (Object e : a)
- if (e == null)
+ for (int i = 0; i < len; i++)
+ if (a[i] == null)
throw new NullPointerException();
this.queue = a;
this.size = a.length;
@@ -406,7 +406,7 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- return indexOf(o) >= 0;
+ return indexOf(o) != -1;
}
/**
@@ -448,7 +448,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -489,7 +489,7 @@
* Index (into queue array) of element to be returned by
* subsequent call to next.
*/
- private int cursor;
+ private int cursor = 0;
/**
* Index of element returned by most recent call to next,
@@ -509,13 +509,13 @@
* We expect that most iterations, even those involving removals,
* will not need to store elements in this field.
*/
- private ArrayDeque<E> forgetMeNot;
+ private ArrayDeque<E> forgetMeNot = null;
/**
* Element returned by the most recent call to next iff that
* element was drawn from the forgetMeNot list.
*/
- private E lastRetElt;
+ private E lastRetElt = null;
/**
* The modCount value that the iterator believes that the backing
@@ -609,8 +609,8 @@
* avoid missing traversing elements.
*/
@SuppressWarnings("unchecked")
- E removeAt(int i) {
- // assert i >= 0 && i < size;
+ private E removeAt(int i) {
+ assert i >= 0 && i < size;
modCount++;
int s = --size;
if (s == i) // removed last element
@@ -756,7 +756,6 @@
* emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
* @param s the stream
- * @throws java.io.IOException if an I/O error occurs
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
@@ -776,9 +775,6 @@
* (that is, deserializes it).
*
* @param s the stream
- * @throws ClassNotFoundException if the class of a serialized object
- * could not be found
- * @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -813,7 +809,7 @@
* @since 1.8
*/
public final Spliterator<E> spliterator() {
- return new PriorityQueueSpliterator<>(this, 0, -1, 0);
+ return new PriorityQueueSpliterator<E>(this, 0, -1, 0);
}
static final class PriorityQueueSpliterator<E> implements Spliterator<E> {
@@ -826,9 +822,9 @@
private int fence; // -1 until first use
private int expectedModCount; // initialized when fence set
- /** Creates new spliterator covering the given range. */
+ /** Creates new spliterator covering the given range */
PriorityQueueSpliterator(PriorityQueue<E> pq, int origin, int fence,
- int expectedModCount) {
+ int expectedModCount) {
this.pq = pq;
this.index = origin;
this.fence = fence;
@@ -847,8 +843,8 @@
public PriorityQueueSpliterator<E> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null :
- new PriorityQueueSpliterator<>(pq, lo, index = mid,
- expectedModCount);
+ new PriorityQueueSpliterator<E>(pq, lo, index = mid,
+ expectedModCount);
}
@SuppressWarnings("unchecked")
diff --git a/ojluni/src/main/java/java/util/Queue.java b/ojluni/src/main/java/java/util/Queue.java
index 6520337..b43c6c1 100644
--- a/ojluni/src/main/java/java/util/Queue.java
+++ b/ojluni/src/main/java/java/util/Queue.java
@@ -50,6 +50,7 @@
* implementations; in most implementations, insert operations cannot
* fail.
*
+ * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of Queue methods</caption>
* <tr>
@@ -127,9 +128,17 @@
* always well-defined for queues with the same elements but different
* ordering properties.
*
+ * @see java.util.Collection
+ * @see LinkedList
+ * @see PriorityQueue
+ * @see java.util.concurrent.LinkedBlockingQueue
+ * @see java.util.concurrent.BlockingQueue
+ * @see java.util.concurrent.ArrayBlockingQueue
+ * @see java.util.concurrent.LinkedBlockingQueue
+ * @see java.util.concurrent.PriorityBlockingQueue
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this queue
+ * @param <E> the type of elements held in this collection
*/
public interface Queue<E> extends Collection<E> {
/**
diff --git a/ojluni/src/main/java/java/util/SplittableRandom.java b/ojluni/src/main/java/java/util/SplittableRandom.java
deleted file mode 100644
index b2a07ec..0000000
--- a/ojluni/src/main/java/java/util/SplittableRandom.java
+++ /dev/null
@@ -1,998 +0,0 @@
-/*
- * Copyright (c) 2013, 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. 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.
- */
-
-package java.util;
-
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.DoubleConsumer;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-import java.util.stream.DoubleStream;
-import java.util.stream.IntStream;
-import java.util.stream.LongStream;
-import java.util.stream.StreamSupport;
-
-
-// TODO(streams): Include in openjdk_java_files.mk
-/**
- * A generator of uniform pseudorandom values applicable for use in
- * (among other contexts) isolated parallel computations that may
- * generate subtasks. Class {@code SplittableRandom} supports methods for
- * producing pseudorandom numbers of type {@code int}, {@code long},
- * and {@code double} with similar usages as for class
- * {@link java.util.Random} but differs in the following ways:
- *
- * <ul>
- *
- * <li>Series of generated values pass the DieHarder suite testing
- * independence and uniformity properties of random number generators.
- * (Most recently validated with <a
- * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
- * 3.31.1</a>.) These tests validate only the methods for certain
- * types and ranges, but similar properties are expected to hold, at
- * least approximately, for others as well. The <em>period</em>
- * (length of any series of generated values before it repeats) is at
- * least 2<sup>64</sup>.
- *
- * <li>Method {@link #split} constructs and returns a new
- * SplittableRandom instance that shares no mutable state with the
- * current instance. However, with very high probability, the
- * values collectively generated by the two objects have the same
- * statistical properties as if the same quantity of values were
- * generated by a single thread using a single {@code
- * SplittableRandom} object.
- *
- * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
- * They are designed to be split, not shared, across threads. For
- * example, a {@link java.util.concurrent.ForkJoinTask
- * fork/join-style} computation using random numbers might include a
- * construction of the form {@code new
- * Subtask(aSplittableRandom.split()).fork()}.
- *
- * <li>This class provides additional methods for generating random
- * streams, that employ the above techniques when used in {@code
- * stream.parallel()} mode.
- *
- * </ul>
- *
- * <p>Instances of {@code SplittableRandom} are not cryptographically
- * secure. Consider instead using {@link java.security.SecureRandom}
- * in security-sensitive applications. Additionally,
- * default-constructed instances do not use a cryptographically random
- * seed unless the {@linkplain System#getProperty system property}
- * {@code java.util.secureRandomSeed} is set to {@code true}.
- *
- * @author Guy Steele
- * @author Doug Lea
- * @since 1.8
- */
-public final class SplittableRandom {
-
- /*
- * Implementation Overview.
- *
- * This algorithm was inspired by the "DotMix" algorithm by
- * Leiserson, Schardl, and Sukha "Deterministic Parallel
- * Random-Number Generation for Dynamic-Multithreading Platforms",
- * PPoPP 2012, as well as those in "Parallel random numbers: as
- * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011. It
- * differs mainly in simplifying and cheapening operations.
- *
- * The primary update step (method nextSeed()) is to add a
- * constant ("gamma") to the current (64 bit) seed, forming a
- * simple sequence. The seed and the gamma values for any two
- * SplittableRandom instances are highly likely to be different.
- *
- * Methods nextLong, nextInt, and derivatives do not return the
- * sequence (seed) values, but instead a hash-like bit-mix of
- * their bits, producing more independently distributed sequences.
- * For nextLong, the mix64 function is based on David Stafford's
- * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
- * "Mix13" variant of the "64-bit finalizer" function in Austin
- * Appleby's MurmurHash3 algorithm (see
- * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32
- * function is based on Stafford's Mix04 mix function, but returns
- * the upper 32 bits cast as int.
- *
- * The split operation uses the current generator to form the seed
- * and gamma for another SplittableRandom. To conservatively
- * avoid potential correlations between seed and value generation,
- * gamma selection (method mixGamma) uses different
- * (Murmurhash3's) mix constants. To avoid potential weaknesses
- * in bit-mixing transformations, we restrict gammas to odd values
- * with at least 24 0-1 or 1-0 bit transitions. Rather than
- * rejecting candidates with too few or too many bits set, method
- * mixGamma flips some bits (which has the effect of mapping at
- * most 4 to any given gamma value). This reduces the effective
- * set of 64bit odd gamma values by about 2%, and serves as an
- * automated screening for sequence constant selection that is
- * left as an empirical decision in some other hashing and crypto
- * algorithms.
- *
- * The resulting generator thus transforms a sequence in which
- * (typically) many bits change on each step, with an inexpensive
- * mixer with good (but less than cryptographically secure)
- * avalanching.
- *
- * The default (no-argument) constructor, in essence, invokes
- * split() for a common "defaultGen" SplittableRandom. Unlike
- * other cases, this split must be performed in a thread-safe
- * manner, so we use an AtomicLong to represent the seed rather
- * than use an explicit SplittableRandom. To bootstrap the
- * defaultGen, we start off using a seed based on current time
- * unless the java.util.secureRandomSeed property is set. This
- * serves as a slimmed-down (and insecure) variant of SecureRandom
- * that also avoids stalls that may occur when using /dev/random.
- *
- * It is a relatively simple matter to apply the basic design here
- * to use 128 bit seeds. However, emulating 128bit arithmetic and
- * carrying around twice the state add more overhead than appears
- * warranted for current usages.
- *
- * File organization: First the non-public methods that constitute
- * the main algorithm, then the main public methods, followed by
- * some custom spliterator classes needed for stream methods.
- */
-
- /**
- * The golden ratio scaled to 64bits, used as the initial gamma
- * value for (unsplit) SplittableRandoms.
- */
- private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
-
- /**
- * The least non-zero value returned by nextDouble(). This value
- * is scaled by a random value of 53 bits to produce a result.
- */
- private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53);
-
- /**
- * The seed. Updated only via method nextSeed.
- */
- private long seed;
-
- /**
- * The step value.
- */
- private final long gamma;
-
- /**
- * Internal constructor used by all others except default constructor.
- */
- private SplittableRandom(long seed, long gamma) {
- this.seed = seed;
- this.gamma = gamma;
- }
-
- /**
- * Computes Stafford variant 13 of 64bit mix function.
- */
- private static long mix64(long z) {
- z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
- z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
- return z ^ (z >>> 31);
- }
-
- /**
- * Returns the 32 high bits of Stafford variant 4 mix64 function as int.
- */
- private static int mix32(long z) {
- z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
- return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
- }
-
- /**
- * Returns the gamma value to use for a new split instance.
- */
- private static long mixGamma(long z) {
- z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants
- z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
- z = (z ^ (z >>> 33)) | 1L; // force to be odd
- int n = Long.bitCount(z ^ (z >>> 1)); // ensure enough transitions
- return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
- }
-
- /**
- * Adds gamma to seed.
- */
- private long nextSeed() {
- return seed += gamma;
- }
-
- // IllegalArgumentException messages
- static final String BAD_BOUND = "bound must be positive";
- static final String BAD_RANGE = "bound must be greater than origin";
- static final String BAD_SIZE = "size must be non-negative";
-
- /**
- * The seed generator for default constructors.
- */
- private static final AtomicLong defaultGen
- = new AtomicLong(mix64(System.currentTimeMillis()) ^
- mix64(System.nanoTime()));
-
- // at end of <clinit> to survive static initialization circularity
- static {
- 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)
- s = (s << 8) | ((long)seedBytes[i] & 0xffL);
- defaultGen.set(s);
- }
- }
-
- /*
- * Internal versions of nextX methods used by streams, as well as
- * the public nextX(origin, bound) methods. These exist mainly to
- * avoid the need for multiple versions of stream spliterators
- * across the different exported forms of streams.
- */
-
- /**
- * The form of nextLong used by LongStream Spliterators. If
- * origin is greater than bound, acts as unbounded form of
- * nextLong, else as bounded form.
- *
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final long internalNextLong(long origin, long bound) {
- /*
- * Four Cases:
- *
- * 1. If the arguments indicate unbounded form, act as
- * nextLong().
- *
- * 2. If the range is an exact power of two, apply the
- * associated bit mask.
- *
- * 3. If the range is positive, loop to avoid potential bias
- * when the implicit nextLong() bound (2<sup>64</sup>) is not
- * evenly divisible by the range. The loop rejects candidates
- * computed from otherwise over-represented values. The
- * expected number of iterations under an ideal generator
- * varies from 1 to 2, depending on the bound. The loop itself
- * takes an unlovable form. Because the first candidate is
- * already available, we need a break-in-the-middle
- * construction, which is concisely but cryptically performed
- * within the while-condition of a body-less for loop.
- *
- * 4. Otherwise, the range cannot be represented as a positive
- * long. The loop repeatedly generates unbounded longs until
- * obtaining a candidate meeting constraints (with an expected
- * number of iterations of less than two).
- */
-
- long r = mix64(nextSeed());
- if (origin < bound) {
- long n = bound - origin, m = n - 1;
- if ((n & m) == 0L) // power of two
- r = (r & m) + origin;
- else if (n > 0L) { // reject over-represented candidates
- for (long u = r >>> 1; // ensure nonnegative
- u + m - (r = u % n) < 0L; // rejection check
- u = mix64(nextSeed()) >>> 1) // retry
- ;
- r += origin;
- }
- else { // range not representable as long
- while (r < origin || r >= bound)
- r = mix64(nextSeed());
- }
- }
- return r;
- }
-
- /**
- * The form of nextInt used by IntStream Spliterators.
- * Exactly the same as long version, except for types.
- *
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final int internalNextInt(int origin, int bound) {
- int r = mix32(nextSeed());
- if (origin < bound) {
- int n = bound - origin, m = n - 1;
- if ((n & m) == 0)
- r = (r & m) + origin;
- else if (n > 0) {
- for (int u = r >>> 1;
- u + m - (r = u % n) < 0;
- u = mix32(nextSeed()) >>> 1)
- ;
- r += origin;
- }
- else {
- while (r < origin || r >= bound)
- r = mix32(nextSeed());
- }
- }
- return r;
- }
-
- /**
- * The form of nextDouble used by DoubleStream Spliterators.
- *
- * @param origin the least value, unless greater than bound
- * @param bound the upper bound (exclusive), must not equal origin
- * @return a pseudorandom value
- */
- final double internalNextDouble(double origin, double bound) {
- double r = (nextLong() >>> 11) * DOUBLE_UNIT;
- if (origin < bound) {
- r = r * (bound - origin) + origin;
- if (r >= bound) // correct for rounding
- r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
- }
- return r;
- }
-
- /* ---------------- public methods ---------------- */
-
- /**
- * Creates a new SplittableRandom instance using the specified
- * initial seed. SplittableRandom instances created with the same
- * seed in the same program generate identical sequences of values.
- *
- * @param seed the initial seed
- */
- public SplittableRandom(long seed) {
- this(seed, GOLDEN_GAMMA);
- }
-
- /**
- * Creates a new SplittableRandom instance that is likely to
- * generate sequences of values that are statistically independent
- * of those of any other instances in the current program; and
- * may, and typically does, vary across program invocations.
- */
- public SplittableRandom() { // emulate defaultGen.split()
- long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA);
- this.seed = mix64(s);
- this.gamma = mixGamma(s + GOLDEN_GAMMA);
- }
-
- /**
- * Constructs and returns a new SplittableRandom instance that
- * shares no mutable state with this instance. However, with very
- * high probability, the set of values collectively generated by
- * the two objects has the same statistical properties as if the
- * same quantity of values were generated by a single thread using
- * a single SplittableRandom object. Either or both of the two
- * objects may be further split using the {@code split()} method,
- * and the same expected statistical properties apply to the
- * entire set of generators constructed by such recursive
- * splitting.
- *
- * @return the new SplittableRandom instance
- */
- public SplittableRandom split() {
- return new SplittableRandom(nextLong(), mixGamma(nextSeed()));
- }
-
- /**
- * Returns a pseudorandom {@code int} value.
- *
- * @return a pseudorandom {@code int} value
- */
- public int nextInt() {
- return mix32(nextSeed());
- }
-
- /**
- * Returns a pseudorandom {@code int} value between zero (inclusive)
- * and the specified bound (exclusive).
- *
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code int} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public int nextInt(int bound) {
- if (bound <= 0)
- throw new IllegalArgumentException(BAD_BOUND);
- // Specialize internalNextInt for origin 0
- int r = mix32(nextSeed());
- int m = bound - 1;
- if ((bound & m) == 0) // power of two
- r &= m;
- else { // reject over-represented candidates
- for (int u = r >>> 1;
- u + m - (r = u % bound) < 0;
- u = mix32(nextSeed()) >>> 1)
- ;
- }
- return r;
- }
-
- /**
- * Returns a pseudorandom {@code int} value between the specified
- * origin (inclusive) and the specified bound (exclusive).
- *
- * @param origin the least value returned
- * @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code int} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
- */
- public int nextInt(int origin, int bound) {
- if (origin >= bound)
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextInt(origin, bound);
- }
-
- /**
- * Returns a pseudorandom {@code long} value.
- *
- * @return a pseudorandom {@code long} value
- */
- public long nextLong() {
- return mix64(nextSeed());
- }
-
- /**
- * Returns a pseudorandom {@code long} value between zero (inclusive)
- * and the specified bound (exclusive).
- *
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code long} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public long nextLong(long bound) {
- if (bound <= 0)
- throw new IllegalArgumentException(BAD_BOUND);
- // Specialize internalNextLong for origin 0
- long r = mix64(nextSeed());
- long m = bound - 1;
- if ((bound & m) == 0L) // power of two
- r &= m;
- else { // reject over-represented candidates
- for (long u = r >>> 1;
- u + m - (r = u % bound) < 0L;
- u = mix64(nextSeed()) >>> 1)
- ;
- }
- return r;
- }
-
- /**
- * Returns a pseudorandom {@code long} value between the specified
- * origin (inclusive) and the specified bound (exclusive).
- *
- * @param origin the least value returned
- * @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code long} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
- */
- public long nextLong(long origin, long bound) {
- if (origin >= bound)
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextLong(origin, bound);
- }
-
- /**
- * Returns a pseudorandom {@code double} value between zero
- * (inclusive) and one (exclusive).
- *
- * @return a pseudorandom {@code double} value between zero
- * (inclusive) and one (exclusive)
- */
- public double nextDouble() {
- return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
- }
-
- /**
- * Returns a pseudorandom {@code double} value between 0.0
- * (inclusive) and the specified bound (exclusive).
- *
- * @param bound the upper bound (exclusive). Must be positive.
- * @return a pseudorandom {@code double} value between zero
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code bound} is not positive
- */
- public double nextDouble(double bound) {
- if (!(bound > 0.0))
- throw new IllegalArgumentException(BAD_BOUND);
- double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
- return (result < bound) ? result : // correct for rounding
- Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
- }
-
- /**
- * Returns a pseudorandom {@code double} value between the specified
- * origin (inclusive) and bound (exclusive).
- *
- * @param origin the least value returned
- * @param bound the upper bound (exclusive)
- * @return a pseudorandom {@code double} value between the origin
- * (inclusive) and the bound (exclusive)
- * @throws IllegalArgumentException if {@code origin} is greater than
- * or equal to {@code bound}
- */
- public double nextDouble(double origin, double bound) {
- if (!(origin < bound))
- throw new IllegalArgumentException(BAD_RANGE);
- return internalNextDouble(origin, bound);
- }
-
- /**
- * Returns a pseudorandom {@code boolean} value.
- *
- * @return a pseudorandom {@code boolean} value
- */
- public boolean nextBoolean() {
- return mix32(nextSeed()) < 0;
- }
-
- // stream methods, coded in a way intended to better isolate for
- // maintenance purposes the small differences across forms.
-
- /**
- * Returns a stream producing the given {@code streamSize} number
- * of pseudorandom {@code int} values from this generator and/or
- * one split from it.
- *
- * @param streamSize the number of values to generate
- * @return a stream of pseudorandom {@code int} values
- * @throws IllegalArgumentException if {@code streamSize} is
- * less than zero
- */
- public IntStream ints(long streamSize) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- return StreamSupport.intStream
- (new RandomIntsSpliterator
- (this, 0L, streamSize, Integer.MAX_VALUE, 0),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code int}
- * values from this generator and/or one split from it.
- *
- * @implNote This method is implemented to be equivalent to {@code
- * ints(Long.MAX_VALUE)}.
- *
- * @return a stream of pseudorandom {@code int} values
- */
- public IntStream ints() {
- return StreamSupport.intStream
- (new RandomIntsSpliterator
- (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
- false);
- }
-
- /**
- * Returns a stream producing the given {@code streamSize} number
- * of pseudorandom {@code int} values from this generator and/or one split
- * from it; each value conforms to the given origin (inclusive) and bound
- * (exclusive).
- *
- * @param streamSize the number of values to generate
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @return a stream of pseudorandom {@code int} values,
- * each with the given origin (inclusive) and bound (exclusive)
- * @throws IllegalArgumentException if {@code streamSize} is
- * less than zero, or {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public IntStream ints(long streamSize, int randomNumberOrigin,
- int randomNumberBound) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.intStream
- (new RandomIntsSpliterator
- (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code
- * int} values from this generator and/or one split from it; each value
- * conforms to the given origin (inclusive) and bound (exclusive).
- *
- * @implNote This method is implemented to be equivalent to {@code
- * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- *
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @return a stream of pseudorandom {@code int} values,
- * each with the given origin (inclusive) and bound (exclusive)
- * @throws IllegalArgumentException if {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
- if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.intStream
- (new RandomIntsSpliterator
- (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Returns a stream producing the given {@code streamSize} number
- * of pseudorandom {@code long} values from this generator and/or
- * one split from it.
- *
- * @param streamSize the number of values to generate
- * @return a stream of pseudorandom {@code long} values
- * @throws IllegalArgumentException if {@code streamSize} is
- * less than zero
- */
- public LongStream longs(long streamSize) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- return StreamSupport.longStream
- (new RandomLongsSpliterator
- (this, 0L, streamSize, Long.MAX_VALUE, 0L),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code
- * long} values from this generator and/or one split from it.
- *
- * @implNote This method is implemented to be equivalent to {@code
- * longs(Long.MAX_VALUE)}.
- *
- * @return a stream of pseudorandom {@code long} values
- */
- public LongStream longs() {
- return StreamSupport.longStream
- (new RandomLongsSpliterator
- (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
- false);
- }
-
- /**
- * Returns a stream producing the given {@code streamSize} number of
- * pseudorandom {@code long} values from this generator and/or one split
- * from it; each value conforms to the given origin (inclusive) and bound
- * (exclusive).
- *
- * @param streamSize the number of values to generate
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @return a stream of pseudorandom {@code long} values,
- * each with the given origin (inclusive) and bound (exclusive)
- * @throws IllegalArgumentException if {@code streamSize} is
- * less than zero, or {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public LongStream longs(long streamSize, long randomNumberOrigin,
- long randomNumberBound) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.longStream
- (new RandomLongsSpliterator
- (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code
- * long} values from this generator and/or one split from it; each value
- * conforms to the given origin (inclusive) and bound (exclusive).
- *
- * @implNote This method is implemented to be equivalent to {@code
- * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- *
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @return a stream of pseudorandom {@code long} values,
- * each with the given origin (inclusive) and bound (exclusive)
- * @throws IllegalArgumentException if {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
- if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.longStream
- (new RandomLongsSpliterator
- (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Returns a stream producing the given {@code streamSize} number of
- * pseudorandom {@code double} values from this generator and/or one split
- * from it; each value is between zero (inclusive) and one (exclusive).
- *
- * @param streamSize the number of values to generate
- * @return a stream of {@code double} values
- * @throws IllegalArgumentException if {@code streamSize} is
- * less than zero
- */
- public DoubleStream doubles(long streamSize) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- return StreamSupport.doubleStream
- (new RandomDoublesSpliterator
- (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code
- * double} values from this generator and/or one split from it; each value
- * is between zero (inclusive) and one (exclusive).
- *
- * @implNote This method is implemented to be equivalent to {@code
- * doubles(Long.MAX_VALUE)}.
- *
- * @return a stream of pseudorandom {@code double} values
- */
- public DoubleStream doubles() {
- return StreamSupport.doubleStream
- (new RandomDoublesSpliterator
- (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
- false);
- }
-
- /**
- * Returns a stream producing the given {@code streamSize} number of
- * pseudorandom {@code double} values from this generator and/or one split
- * from it; each value conforms to the given origin (inclusive) and bound
- * (exclusive).
- *
- * @param streamSize the number of values to generate
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @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
- * @throws IllegalArgumentException if {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public DoubleStream doubles(long streamSize, double randomNumberOrigin,
- double randomNumberBound) {
- if (streamSize < 0L)
- throw new IllegalArgumentException(BAD_SIZE);
- if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.doubleStream
- (new RandomDoublesSpliterator
- (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Returns an effectively unlimited stream of pseudorandom {@code
- * double} values from this generator and/or one split from it; each value
- * conforms to the given origin (inclusive) and bound (exclusive).
- *
- * @implNote This method is implemented to be equivalent to {@code
- * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
- *
- * @param randomNumberOrigin the origin (inclusive) of each random value
- * @param randomNumberBound the bound (exclusive) of each random value
- * @return a stream of pseudorandom {@code double} values,
- * each with the given origin (inclusive) and bound (exclusive)
- * @throws IllegalArgumentException if {@code randomNumberOrigin}
- * is greater than or equal to {@code randomNumberBound}
- */
- public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
- if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BAD_RANGE);
- return StreamSupport.doubleStream
- (new RandomDoublesSpliterator
- (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
- false);
- }
-
- /**
- * Spliterator for int streams. We multiplex the four int
- * versions into one class by treating a bound less than origin as
- * unbounded, and also by treating "infinite" as equivalent to
- * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
- * approach. The long and double versions of this class are
- * identical except for types.
- */
- private static final class RandomIntsSpliterator
- implements Spliterator.OfInt {
- final SplittableRandom rng;
- long index;
- final long fence;
- final int origin;
- final int bound;
- RandomIntsSpliterator(SplittableRandom rng, long index, long fence,
- int origin, int bound) {
- this.rng = rng; this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomIntsSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(IntConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(rng.internalNextInt(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(IntConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- SplittableRandom r = rng;
- int o = origin, b = bound;
- do {
- consumer.accept(r.internalNextInt(o, b));
- } while (++i < f);
- }
- }
- }
-
- /**
- * Spliterator for long streams.
- */
- private static final class RandomLongsSpliterator
- implements Spliterator.OfLong {
- final SplittableRandom rng;
- long index;
- final long fence;
- final long origin;
- final long bound;
- RandomLongsSpliterator(SplittableRandom rng, long index, long fence,
- long origin, long bound) {
- this.rng = rng; this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomLongsSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(LongConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(rng.internalNextLong(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(LongConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- SplittableRandom r = rng;
- long o = origin, b = bound;
- do {
- consumer.accept(r.internalNextLong(o, b));
- } while (++i < f);
- }
- }
-
- }
-
- /**
- * Spliterator for double streams.
- */
- private static final class RandomDoublesSpliterator
- implements Spliterator.OfDouble {
- final SplittableRandom rng;
- long index;
- final long fence;
- final double origin;
- final double bound;
- RandomDoublesSpliterator(SplittableRandom rng, long index, long fence,
- double origin, double bound) {
- this.rng = rng; this.index = index; this.fence = fence;
- this.origin = origin; this.bound = bound;
- }
-
- public RandomDoublesSpliterator trySplit() {
- long i = index, m = (i + fence) >>> 1;
- return (m <= i) ? null :
- new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound);
- }
-
- public long estimateSize() {
- return fence - index;
- }
-
- public int characteristics() {
- return (Spliterator.SIZED | Spliterator.SUBSIZED |
- Spliterator.NONNULL | Spliterator.IMMUTABLE);
- }
-
- public boolean tryAdvance(DoubleConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- consumer.accept(rng.internalNextDouble(origin, bound));
- index = i + 1;
- return true;
- }
- return false;
- }
-
- public void forEachRemaining(DoubleConsumer consumer) {
- if (consumer == null) throw new NullPointerException();
- long i = index, f = fence;
- if (i < f) {
- index = f;
- SplittableRandom r = rng;
- double o = origin, b = bound;
- do {
- consumer.accept(r.internalNextDouble(o, b));
- } while (++i < f);
- }
- }
- }
-
-}