8186056: Miscellaneous changes imported from jsr166 CVS 2017-09
Reviewed-by: martin, psandoz
--- a/src/java.base/share/classes/java/util/ArrayDeque.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Tue Oct 03 14:00:00 2017 -0700
@@ -211,7 +211,7 @@
}
/**
- * Increments i, mod modulus.
+ * Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int inc(int i, int modulus) {
@@ -220,7 +220,7 @@
}
/**
- * Decrements i, mod modulus.
+ * Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int dec(int i, int modulus) {
@@ -233,7 +233,7 @@
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
* @return index 0 <= i < modulus
*/
- static final int add(int i, int distance, int modulus) {
+ static final int inc(int i, int distance, int modulus) {
if ((i += distance) - modulus >= 0) i -= modulus;
return i;
}
@@ -825,7 +825,7 @@
final int i, n;
return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
? null
- : new DeqSpliterator(i, cursor = add(i, n, es.length));
+ : new DeqSpliterator(i, cursor = inc(i, n, es.length));
}
public void forEachRemaining(Consumer<? super E> action) {
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Oct 03 14:00:00 2017 -0700
@@ -1394,8 +1394,8 @@
}
/**
- * Saves the state of the {@code ConcurrentHashMap} instance to a
- * stream (i.e., serializes it).
+ * 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
@@ -1439,7 +1439,7 @@
}
/**
- * Reconstitutes the instance from a stream (that is, deserializes it).
+ * 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
--- a/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Tue Oct 03 14:00:00 2017 -0700
@@ -174,6 +174,10 @@
this.completionQueue = completionQueue;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
@@ -181,6 +185,10 @@
return f;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Tue Oct 03 14:00:00 2017 -0700
@@ -383,7 +383,7 @@
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
- private static final int CAPACITY = (1 << COUNT_BITS) - 1;
+ private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
@@ -393,8 +393,8 @@
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- private static int workerCountOf(int c) { return c & CAPACITY; }
+ private static int runStateOf(int c) { return c & ~COUNT_MASK; }
+ private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
@@ -434,7 +434,7 @@
* decrements are performed within getTask.
*/
private void decrementWorkerCount() {
- do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+ ctl.addAndGet(-1);
}
/**
@@ -538,12 +538,17 @@
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code corePoolSize & COUNT_MASK}.
*/
private volatile int corePoolSize;
/**
- * Maximum pool size. Note that the actual maximum is internally
- * bounded by CAPACITY.
+ * Maximum pool size.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
*/
private volatile int maximumPoolSize;
@@ -705,7 +710,7 @@
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
- (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+ (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
@@ -744,17 +749,12 @@
* specially.
*/
private void checkShutdownAccess() {
+ // assert mainLock.isHeldByCurrentThread();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- security.checkAccess(w.thread);
- } finally {
- mainLock.unlock();
- }
+ for (Worker w : workers)
+ security.checkAccess(w.thread);
}
}
@@ -763,14 +763,9 @@
* (in which case some threads may remain uninterrupted).
*/
private void interruptWorkers() {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- w.interruptIfStarted();
- } finally {
- mainLock.unlock();
- }
+ // assert mainLock.isHeldByCurrentThread();
+ for (Worker w : workers)
+ w.interruptIfStarted();
}
/**
@@ -896,26 +891,22 @@
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
-
+ for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN &&
- ! (rs == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty()))
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP)
+ || firstTask != null
+ || workQueue.isEmpty()))
return false;
for (;;) {
- int wc = workerCountOf(c);
- if (wc >= CAPACITY ||
- wc >= (core ? corePoolSize : maximumPoolSize))
+ if (workerCountOf(c)
+ >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
- if (runStateOf(c) != rs)
+ if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
@@ -934,10 +925,10 @@
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
- int rs = runStateOf(ctl.get());
+ int c = ctl.get();
- if (rs < SHUTDOWN ||
- (rs == SHUTDOWN && firstTask == null)) {
+ if (isRunning(c) ||
+ (runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
@@ -1044,10 +1035,10 @@
for (;;) {
int c = ctl.get();
- int rs = runStateOf(c);
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
@@ -1140,17 +1131,12 @@
wt.interrupt();
try {
beforeExecute(wt, task);
- Throwable thrown = null;
try {
task.run();
- } catch (RuntimeException x) {
- thrown = x; throw x;
- } catch (Error x) {
- thrown = x; throw x;
- } catch (Throwable x) {
- thrown = x; throw new Error(x);
- } finally {
- afterExecute(task, thrown);
+ afterExecute(task, null);
+ } catch (Throwable ex) {
+ afterExecute(task, ex);
+ throw ex;
}
} finally {
task = null;
@@ -1331,7 +1317,7 @@
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
- * the task is handled by the current {@code RejectedExecutionHandler}.
+ * the task is handled by the current {@link RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
@@ -1438,7 +1424,7 @@
}
public boolean isShutdown() {
- return ! isRunning(ctl.get());
+ return runStateAtLeast(ctl.get(), SHUTDOWN);
}
/** Used by ScheduledThreadPoolExecutor. */
@@ -1459,7 +1445,7 @@
*/
public boolean isTerminating() {
int c = ctl.get();
- return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+ return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
@@ -1472,7 +1458,7 @@
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
- while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+ while (runStateLessThan(ctl.get(), TERMINATED)) {
if (nanos <= 0L)
return false;
nanos = termination.awaitNanos(nanos);
@@ -1951,7 +1937,7 @@
}
int c = ctl.get();
String runState =
- runStateLessThan(c, SHUTDOWN) ? "Running" :
+ isRunning(c) ? "Running" :
runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down";
return super.toString() +
--- a/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Tue Oct 03 14:00:00 2017 -0700
@@ -342,11 +342,13 @@
* using:
*
* <pre> {@code
- * public synchronized Object poll(long timeout, TimeUnit unit)
+ * public E poll(long timeout, TimeUnit unit)
* throws InterruptedException {
- * while (empty) {
- * unit.timedWait(this, timeout);
- * ...
+ * synchronized (lock) {
+ * while (isEmpty()) {
+ * unit.timedWait(lock, timeout);
+ * ...
+ * }
* }
* }}</pre>
*
--- a/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Tue Oct 03 13:55:05 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Tue Oct 03 14:00:00 2017 -0700
@@ -73,7 +73,7 @@
* available in the buffer. This can be achieved using two
* {@link Condition} instances.
* <pre>
- * class BoundedBuffer {
+ * class BoundedBuffer<E> {
* <b>final Lock lock = new ReentrantLock();</b>
* final Condition notFull = <b>lock.newCondition(); </b>
* final Condition notEmpty = <b>lock.newCondition(); </b>
@@ -81,7 +81,7 @@
* final Object[] items = new Object[100];
* int putptr, takeptr, count;
*
- * public void put(Object x) throws InterruptedException {
+ * public void put(E x) throws InterruptedException {
* <b>lock.lock();
* try {</b>
* while (count == items.length)
@@ -95,12 +95,12 @@
* }</b>
* }
*
- * public Object take() throws InterruptedException {
+ * public E take() throws InterruptedException {
* <b>lock.lock();
* try {</b>
* while (count == 0)
* <b>notEmpty.await();</b>
- * Object x = items[takeptr];
+ * E x = (E) items[takeptr];
* if (++takeptr == items.length) takeptr = 0;
* --count;
* <b>notFull.signal();</b>
@@ -310,7 +310,8 @@
* the following form:
*
* <pre> {@code
- * boolean aMethod(long timeout, TimeUnit unit) {
+ * boolean aMethod(long timeout, TimeUnit unit)
+ * throws InterruptedException {
* long nanos = unit.toNanos(timeout);
* lock.lock();
* try {
@@ -320,6 +321,7 @@
* nanos = theCondition.awaitNanos(nanos);
* }
* // ...
+ * return true;
* } finally {
* lock.unlock();
* }
@@ -410,7 +412,8 @@
* <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows:
* <pre> {@code
- * boolean aMethod(Date deadline) {
+ * boolean aMethod(Date deadline)
+ * throws InterruptedException {
* boolean stillWaiting = true;
* lock.lock();
* try {
@@ -420,6 +423,7 @@
* stillWaiting = theCondition.awaitUntil(deadline);
* }
* // ...
+ * return true;
* } finally {
* lock.unlock();
* }
--- a/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Tue Oct 03 14:00:00 2017 -0700
@@ -36,12 +36,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
-import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.Map;
import java.util.PriorityQueue;
import java.util.Spliterator;
import java.util.Vector;
@@ -52,7 +50,6 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
--- a/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Tue Oct 03 14:00:00 2017 -0700
@@ -29,20 +29,16 @@
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
-import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
-import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
-import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
--- a/test/jdk/java/util/Collection/testlibrary/CollectionAsserts.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/Collection/testlibrary/CollectionAsserts.java Tue Oct 03 14:00:00 2017 -0700
@@ -23,7 +23,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
--- a/test/jdk/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Tue Oct 03 14:00:00 2017 -0700
@@ -21,8 +21,6 @@
* questions.
*/
import java.util.AbstractCollection;
-import java.util.HashSet;
-import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
--- a/test/jdk/java/util/List/ListDefaults.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/List/ListDefaults.java Tue Oct 03 14:00:00 2017 -0700
@@ -42,12 +42,10 @@
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
-import java.lang.reflect.Constructor;
import java.util.ConcurrentModificationException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.function.Supplier;
/**
* @test
--- a/test/jdk/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Tue Oct 03 14:00:00 2017 -0700
@@ -43,7 +43,6 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -55,26 +54,18 @@
extends ConcurrentHashMap<Class<?>, Integer> {
void inc(Class<?> key) {
- for (;;) {
- Integer i = get(key);
- if (i == null) {
- if (putIfAbsent(key, 1) == null)
- return;
- } else {
- if (replace(key, i, i + 1))
- return;
- }
- }
+ compute(key, (k, v) -> (v == null) ? 1 : v + 1);
}
}
+ /** Double-check that HashTable and ConcurrentHashMap are work-alikes. */
@SuppressWarnings("serial")
static class UncaughtExceptionsTable
extends Hashtable<Class<?>, Integer> {
synchronized void inc(Class<?> key) {
- Integer i = get(key);
- put(key, (i == null) ? 1 : i + 1);
+ Integer v = get(key);
+ put(key, (v == null) ? 1 : v + 1);
}
}
@@ -82,37 +73,20 @@
= new UncaughtExceptions();
static final UncaughtExceptionsTable uncaughtExceptionsTable
= new UncaughtExceptionsTable();
- static final AtomicLong totalUncaughtExceptions
- = new AtomicLong(0);
+ static final AtomicInteger totalUncaughtExceptions
+ = new AtomicInteger(0);
static final CountDownLatch uncaughtExceptionsLatch
= new CountDownLatch(24);
- static final Thread.UncaughtExceptionHandler handler
- = new Thread.UncaughtExceptionHandler() {
- public void uncaughtException(Thread t, Throwable e) {
- check(! Thread.currentThread().isInterrupted());
- totalUncaughtExceptions.getAndIncrement();
- uncaughtExceptions.inc(e.getClass());
- uncaughtExceptionsTable.inc(e.getClass());
- uncaughtExceptionsLatch.countDown();
- }};
-
static final ThreadGroup tg = new ThreadGroup("Flaky");
- static final ThreadFactory tf = new ThreadFactory() {
- public Thread newThread(Runnable r) {
- Thread t = new Thread(tg, r);
- t.setUncaughtExceptionHandler(handler);
- return t;
- }};
-
static final RuntimeException rte = new RuntimeException();
static final Error error = new Error();
static final Throwable weird = new Throwable();
static final Exception checkedException = new Exception();
static class Thrower implements Runnable {
- Throwable t;
+ final Throwable t;
Thrower(Throwable t) { this.t = t; }
public void run() {
if (t != null)
@@ -120,14 +94,12 @@
}
}
- static final Thrower noThrower = new Thrower(null);
- static final Thrower rteThrower = new Thrower(rte);
- static final Thrower errorThrower = new Thrower(error);
- static final Thrower weirdThrower = new Thrower(weird);
- static final Thrower checkedThrower = new Thrower(checkedException);
-
static final List<Thrower> throwers = Arrays.asList(
- noThrower, rteThrower, errorThrower, weirdThrower, checkedThrower);
+ new Thrower(null),
+ new Thrower(rte),
+ new Thrower(error),
+ new Thrower(weird),
+ new Thrower(checkedException));
static class Flaky implements Runnable {
final Runnable beforeExecute;
@@ -190,7 +162,18 @@
super(10, 10,
1L, TimeUnit.HOURS,
new LinkedBlockingQueue<Runnable>(),
- tf);
+ (ThreadFactory) (runnable) -> {
+ Thread thread = new Thread(tg, runnable);
+ Thread.UncaughtExceptionHandler handler = (t, e) -> {
+ check(! t.isInterrupted());
+ totalUncaughtExceptions.getAndIncrement();
+ uncaughtExceptions.inc(e.getClass());
+ uncaughtExceptionsTable.inc(e.getClass());
+ uncaughtExceptionsLatch.countDown();
+ };
+ thread.setUncaughtExceptionHandler(handler);
+ return thread;
+ });
}
@Override protected void beforeExecute(Thread t, Runnable r) {
final boolean lessThanCorePoolSize;
@@ -262,19 +245,17 @@
check(tpe.awaitTermination(10L, TimeUnit.MINUTES));
checkTerminated(tpe);
- //while (tg.activeCount() > 0) Thread.sleep(10);
- //System.out.println(uncaughtExceptions);
List<Map<Class<?>, Integer>> maps = new ArrayList<>();
maps.add(uncaughtExceptions);
maps.add(uncaughtExceptionsTable);
for (Map<Class<?>, Integer> map : maps) {
- equal(map.get(Exception.class), throwers.size());
- equal(map.get(weird.getClass()), throwers.size());
- equal(map.get(Error.class), throwers.size() + 1 + 2);
+ equal(map.get(Exception.class), throwers.size() + 1);
+ equal(map.get(weird.getClass()), throwers.size() + 1);
+ equal(map.get(Error.class), throwers.size() + 1);
equal(map.get(RuntimeException.class), throwers.size() + 1);
equal(map.size(), 4);
}
- equal(totalUncaughtExceptions.get(), 4L*throwers.size() + 4L);
+ equal(totalUncaughtExceptions.get(), 4*throwers.size() + 4);
equal(beforeExecuteCount.get(), flakes.size());
equal(afterExecuteCount.get(), throwers.size());
--- a/test/jdk/java/util/concurrent/tck/Collection8Test.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Tue Oct 03 14:00:00 2017 -0700
@@ -86,9 +86,9 @@
Object bomb() {
return new Object() {
- public boolean equals(Object x) { throw new AssertionError(); }
- public int hashCode() { throw new AssertionError(); }
- };
+ public boolean equals(Object x) { throw new AssertionError(); }
+ public int hashCode() { throw new AssertionError(); }
+ };
}
/** Checks properties of empty collections. */
--- a/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java Tue Oct 03 14:00:00 2017 -0700
@@ -801,7 +801,7 @@
}
/**
- * transfer waits until a poll occurs. The transfered element
+ * transfer waits until a poll occurs. The transferred element
* is returned by the associated poll.
*/
public void testTransfer2() throws InterruptedException {
@@ -882,7 +882,7 @@
}
/**
- * transfer waits until a take occurs. The transfered element
+ * transfer waits until a take occurs. The transferred element
* is returned by the associated take.
*/
public void testTransfer5() throws InterruptedException {
--- a/test/jdk/java/util/concurrent/tck/StampedLockTest.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/StampedLockTest.java Tue Oct 03 14:00:00 2017 -0700
@@ -1207,4 +1207,90 @@
}
assertUnlocked(lock);
}
+
+ /**
+ * Stamped locks are not reentrant.
+ */
+ public void testNonReentrant() throws InterruptedException {
+ final StampedLock lock = new StampedLock();
+ long stamp;
+
+ stamp = lock.writeLock();
+ assertValid(lock, stamp);
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertEquals(0L, lock.tryReadLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockWrite(stamp);
+
+ stamp = lock.tryWriteLock(1L, DAYS);
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockWrite(stamp);
+
+ stamp = lock.readLock();
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockRead(stamp);
+ }
+
+ /**
+ * """StampedLocks have no notion of ownership. Locks acquired in
+ * one thread can be released or converted in another."""
+ */
+ public void testNoOwnership() throws Throwable {
+ ArrayList<Future<?>> futures = new ArrayList<>();
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ StampedLock lock = new StampedLock();
+ long stamp = writeLocker.apply(lock);
+ futures.add(cachedThreadPool.submit(new CheckedRunnable() {
+ public void realRun() {
+ writeUnlocker.accept(lock, stamp);
+ assertUnlocked(lock);
+ assertFalse(lock.validate(stamp));
+ }}));
+ }
+ for (Future<?> future : futures)
+ assertNull(future.get());
+ }
+
+ /** Tries out sample usage code from StampedLock javadoc. */
+ public void testSampleUsage() throws Throwable {
+ 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
+ double currentX, currentY;
+ long stamp = sl.tryOptimisticRead();
+ do {
+ if (stamp == 0L)
+ stamp = sl.readLock();
+ try {
+ // possibly racy reads
+ currentX = x;
+ currentY = y;
+ } finally {
+ stamp = sl.tryConvertToOptimisticRead(stamp);
+ }
+ } while (stamp == 0);
+ return Math.hypot(currentX, currentY);
+ }
+ }
+
+ Point p = new Point();
+ p.move(3.0, 4.0);
+ assertEquals(5.0, p.distanceFromOrigin());
+ }
+
}
--- a/test/jdk/java/util/concurrent/tck/ThreadLocalRandomTest.java Tue Oct 03 13:55:05 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ThreadLocalRandomTest.java Tue Oct 03 14:00:00 2017 -0700
@@ -84,6 +84,9 @@
* possible values.
*/
public void testNext() throws ReflectiveOperationException {
+ // Inhibit "An illegal reflective access operation has occurred"
+ if (!testImplementationDetails) return;
+
ThreadLocalRandom rnd = ThreadLocalRandom.current();
final java.lang.reflect.Method m;
try {