mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-06 19:59:17 +00:00
8234131: Miscellaneous changes imported from jsr166 CVS 2021-01
8257671: ThreadPoolExecutor.Discard*Policy: rejected tasks are not cancelled Reviewed-by: alanb, prappo, dl
This commit is contained in:
parent
63e3bd7613
commit
270014ab4e
@ -54,13 +54,13 @@ import java.util.List;
|
||||
* to return {@code RunnableFuture} implementations other than
|
||||
* {@code FutureTask}.
|
||||
*
|
||||
* <p><b>Extension example</b>. Here is a sketch of a class
|
||||
* <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
|
||||
* public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
*
|
||||
* static class CustomTask<V> implements RunnableFuture<V> {...}
|
||||
* static class CustomTask<V> implements RunnableFuture<V> { ... }
|
||||
*
|
||||
* protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
|
||||
* return new CustomTask<V>(c);
|
||||
|
||||
@ -69,7 +69,7 @@ import java.util.function.Predicate;
|
||||
* perform some action upon state updates.
|
||||
*
|
||||
* <pre> {@code
|
||||
* class Handler { void handle(); ... }
|
||||
* class Handler { void handle() { ... } }
|
||||
*
|
||||
* class X {
|
||||
* private final CopyOnWriteArraySet<Handler> handlers
|
||||
|
||||
@ -118,7 +118,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* class Driver2 { // ...
|
||||
* void main() throws InterruptedException {
|
||||
* CountDownLatch doneSignal = new CountDownLatch(N);
|
||||
* Executor e = ...
|
||||
* Executor e = ...;
|
||||
*
|
||||
* for (int i = 0; i < N; ++i) // create and start threads
|
||||
* e.execute(new WorkerRunnable(doneSignal, i));
|
||||
@ -135,10 +135,8 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* this.i = i;
|
||||
* }
|
||||
* public void run() {
|
||||
* try {
|
||||
* doWork(i);
|
||||
* doneSignal.countDown();
|
||||
* } catch (InterruptedException ex) {} // return;
|
||||
* doWork();
|
||||
* doneSignal.countDown();
|
||||
* }
|
||||
*
|
||||
* void doWork() { ... }
|
||||
|
||||
@ -94,7 +94,9 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*
|
||||
* // wait until done
|
||||
* for (Thread thread : threads)
|
||||
* thread.join();
|
||||
* try {
|
||||
* thread.join();
|
||||
* } catch (InterruptedException ex) { }
|
||||
* }
|
||||
* }}</pre>
|
||||
*
|
||||
|
||||
@ -57,8 +57,8 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* <pre> {@code
|
||||
* class FillAndEmpty {
|
||||
* Exchanger<DataBuffer> exchanger = new Exchanger<>();
|
||||
* DataBuffer initialEmptyBuffer = ... a made-up type
|
||||
* DataBuffer initialFullBuffer = ...
|
||||
* DataBuffer initialEmptyBuffer = ...; // a made-up type
|
||||
* DataBuffer initialFullBuffer = ...;
|
||||
*
|
||||
* class FillingLoop implements Runnable {
|
||||
* public void run() {
|
||||
@ -69,7 +69,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* if (currentBuffer.isFull())
|
||||
* currentBuffer = exchanger.exchange(currentBuffer);
|
||||
* }
|
||||
* } catch (InterruptedException ex) { ... handle ... }
|
||||
* } catch (InterruptedException ex) { ... handle ...}
|
||||
* }
|
||||
* }
|
||||
*
|
||||
|
||||
@ -117,7 +117,7 @@ import java.util.List;
|
||||
* if (!pool.awaitTermination(60, TimeUnit.SECONDS))
|
||||
* System.err.println("Pool did not terminate");
|
||||
* }
|
||||
* } catch (InterruptedException ie) {
|
||||
* } catch (InterruptedException ex) {
|
||||
* // (Re-)Cancel if current thread also interrupted
|
||||
* pool.shutdownNow();
|
||||
* // Preserve interrupt status
|
||||
|
||||
@ -56,8 +56,8 @@ package java.util.concurrent;
|
||||
* <pre> {@code
|
||||
* interface ArchiveSearcher { String search(String target); }
|
||||
* class App {
|
||||
* ExecutorService executor = ...
|
||||
* ArchiveSearcher searcher = ...
|
||||
* ExecutorService executor = ...;
|
||||
* ArchiveSearcher searcher = ...;
|
||||
* void showSearch(String target) throws InterruptedException {
|
||||
* Callable<String> task = () -> searcher.search(target);
|
||||
* Future<String> future = executor.submit(task);
|
||||
@ -88,25 +88,28 @@ package java.util.concurrent;
|
||||
public interface Future<V> {
|
||||
|
||||
/**
|
||||
* Attempts to cancel execution of this task. This attempt will
|
||||
* fail if the task has already completed, has already been cancelled,
|
||||
* or could not be cancelled for some other reason. If successful,
|
||||
* and this task has not started when {@code cancel} is called,
|
||||
* this task should never run. If the task has already started,
|
||||
* then the {@code mayInterruptIfRunning} parameter determines
|
||||
* whether the thread executing this task should be interrupted in
|
||||
* an attempt to stop the task.
|
||||
* Attempts to cancel execution of this task. This method has no
|
||||
* effect if the task is already completed or cancelled, or could
|
||||
* not be cancelled for some other reason. Otherwise, if this
|
||||
* task has not started when {@code cancel} is called, this task
|
||||
* should never run. If the task has already started, then the
|
||||
* {@code mayInterruptIfRunning} parameter determines whether the
|
||||
* thread executing this task (when known by the implementation)
|
||||
* is interrupted in an attempt to stop the task.
|
||||
*
|
||||
* <p>After this method returns, subsequent calls to {@link #isDone} will
|
||||
* always return {@code true}. Subsequent calls to {@link #isCancelled}
|
||||
* will always return {@code true} if this method returned {@code true}.
|
||||
* <p>The return value from this method does not necessarily
|
||||
* indicate whether the task is now cancelled; use {@link
|
||||
* #isCancelled}.
|
||||
*
|
||||
* @param mayInterruptIfRunning {@code true} if the thread executing this
|
||||
* task should be interrupted; otherwise, in-progress tasks are allowed
|
||||
* to complete
|
||||
* @param mayInterruptIfRunning {@code true} if the thread
|
||||
* executing this task should be interrupted (if the thread is
|
||||
* known to the implementation); otherwise, in-progress tasks are
|
||||
* allowed to complete
|
||||
* @return {@code false} if the task could not be cancelled,
|
||||
* typically because it has already completed normally;
|
||||
* {@code true} otherwise
|
||||
* typically because it has already completed; {@code true}
|
||||
* otherwise. If two or more threads cause a task to be cancelled,
|
||||
* then at least one of them returns {@code true}. Implementations
|
||||
* may provide stronger guarantees.
|
||||
*/
|
||||
boolean cancel(boolean mayInterruptIfRunning);
|
||||
|
||||
|
||||
@ -245,7 +245,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* be appropriate for extremely small per-phase task bodies (thus
|
||||
* high rates), or up to hundreds for extremely large ones.
|
||||
*
|
||||
* <p><b>Implementation notes</b>: This implementation restricts the
|
||||
* <p><b>Implementation notes:</b> This implementation restricts the
|
||||
* maximum number of parties to 65535. Attempts to register additional
|
||||
* parties result in {@code IllegalStateException}. However, you can and
|
||||
* should create tiered phasers to accommodate arbitrarily large sets
|
||||
@ -919,7 +919,7 @@ public class Phaser {
|
||||
* <pre> {@code
|
||||
* Phaser phaser = new Phaser() {
|
||||
* protected boolean onAdvance(int phase, int parties) { return false; }
|
||||
* }}</pre>
|
||||
* };}</pre>
|
||||
*
|
||||
* @param phase the current phase number on entry to this method,
|
||||
* before this phaser is advanced
|
||||
|
||||
@ -87,7 +87,7 @@ import jdk.internal.util.ArraysSupport;
|
||||
* <pre> {@code
|
||||
* class FIFOEntry<E extends Comparable<? super E>>
|
||||
* implements Comparable<FIFOEntry<E>> {
|
||||
* static final AtomicLong seq = new AtomicLong(0);
|
||||
* static final AtomicLong seq = new AtomicLong();
|
||||
* final long seqNum;
|
||||
* final E entry;
|
||||
* public FIFOEntry(E entry) {
|
||||
@ -290,7 +290,9 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
if (allocationSpinLock == 0 &&
|
||||
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
|
||||
try {
|
||||
int growth = oldCap < 64 ? oldCap + 2 : oldCap >> 1;
|
||||
int growth = (oldCap < 64)
|
||||
? (oldCap + 2) // grow faster if small
|
||||
: (oldCap >> 1);
|
||||
int newCap = ArraysSupport.newLength(oldCap, 1, growth);
|
||||
if (queue == array)
|
||||
newArray = new Object[newCap];
|
||||
|
||||
@ -66,7 +66,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
*
|
||||
* // Not a particularly efficient data structure; just for demo
|
||||
*
|
||||
* protected Object[] items = ... whatever kinds of items being managed
|
||||
* protected Object[] items = ...; // whatever kinds of items being managed
|
||||
* protected boolean[] used = new boolean[MAX_AVAILABLE];
|
||||
*
|
||||
* protected synchronized Object getNextAvailableItem() {
|
||||
|
||||
@ -41,6 +41,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
@ -175,11 +176,11 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
/*
|
||||
* Most mechanics are handled by BufferedSubscription. This class
|
||||
* mainly tracks subscribers and ensures sequentiality, by using
|
||||
* built-in synchronization locks across public methods. Using
|
||||
* built-in locks works well in the most typical case in which
|
||||
* only one thread submits items. We extend this idea in
|
||||
* submission methods by detecting single-ownership to reduce
|
||||
* producer-consumer synchronization strength.
|
||||
* locks across public methods, to ensure thread-safety in the
|
||||
* presence of multiple sources and maintain acquire-release
|
||||
* ordering around user operations. However, we also track whether
|
||||
* there is only a single source, and if so streamline some buffer
|
||||
* operations by avoiding some atomics.
|
||||
*/
|
||||
|
||||
/** The largest possible power of two array size. */
|
||||
@ -234,6 +235,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
BufferedSubscription<T> clients;
|
||||
|
||||
/** Lock for exclusion across multiple sources */
|
||||
final ReentrantLock lock;
|
||||
/** Run status, updated only within locks */
|
||||
volatile boolean closed;
|
||||
/** Set true on first call to subscribe, to initialize possible owner */
|
||||
@ -274,6 +277,7 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
throw new NullPointerException();
|
||||
if (maxBufferCapacity <= 0)
|
||||
throw new IllegalArgumentException("capacity must be positive");
|
||||
this.lock = new ReentrantLock();
|
||||
this.executor = executor;
|
||||
this.onNextHandler = handler;
|
||||
this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
|
||||
@ -337,13 +341,15 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
public void subscribe(Subscriber<? super T> subscriber) {
|
||||
if (subscriber == null) throw new NullPointerException();
|
||||
ReentrantLock lock = this.lock;
|
||||
int max = maxBufferCapacity; // allocate initial array
|
||||
Object[] array = new Object[max < INITIAL_CAPACITY ?
|
||||
max : INITIAL_CAPACITY];
|
||||
BufferedSubscription<T> subscription =
|
||||
new BufferedSubscription<T>(subscriber, executor, onNextHandler,
|
||||
array, max);
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!subscribed) {
|
||||
subscribed = true;
|
||||
owner = Thread.currentThread();
|
||||
@ -378,6 +384,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
pred = b;
|
||||
b = next;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,7 +398,9 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
if (item == null) throw new NullPointerException();
|
||||
int lag = 0;
|
||||
boolean complete, unowned;
|
||||
synchronized (this) {
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Thread t = Thread.currentThread(), o;
|
||||
BufferedSubscription<T> b = clients;
|
||||
if ((unowned = ((o = owner) != t)) && o != null)
|
||||
@ -421,6 +431,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
if (retries != null || cleanMe)
|
||||
lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (complete)
|
||||
throw new IllegalStateException("Closed");
|
||||
@ -609,14 +621,18 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
* subscribers have yet completed.
|
||||
*/
|
||||
public void close() {
|
||||
ReentrantLock lock = this.lock;
|
||||
if (!closed) {
|
||||
BufferedSubscription<T> b;
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
// no need to re-check closed here
|
||||
b = clients;
|
||||
clients = null;
|
||||
owner = null;
|
||||
closed = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
while (b != null) {
|
||||
BufferedSubscription<T> next = b.next;
|
||||
@ -641,9 +657,11 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
public void closeExceptionally(Throwable error) {
|
||||
if (error == null)
|
||||
throw new NullPointerException();
|
||||
ReentrantLock lock = this.lock;
|
||||
if (!closed) {
|
||||
BufferedSubscription<T> b;
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
b = clients;
|
||||
if (!closed) { // don't clobber racing close
|
||||
closedException = error;
|
||||
@ -651,6 +669,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
owner = null;
|
||||
closed = true;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
while (b != null) {
|
||||
BufferedSubscription<T> next = b.next;
|
||||
@ -688,7 +708,9 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
public boolean hasSubscribers() {
|
||||
boolean nonEmpty = false;
|
||||
synchronized (this) {
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
for (BufferedSubscription<T> b = clients; b != null;) {
|
||||
BufferedSubscription<T> next = b.next;
|
||||
if (b.isClosed()) {
|
||||
@ -700,6 +722,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return nonEmpty;
|
||||
}
|
||||
@ -710,9 +734,15 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
* @return the number of current subscribers
|
||||
*/
|
||||
public int getNumberOfSubscribers() {
|
||||
synchronized (this) {
|
||||
return cleanAndCount();
|
||||
int n;
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
n = cleanAndCount();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -742,7 +772,9 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
public List<Subscriber<? super T>> getSubscribers() {
|
||||
ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
|
||||
synchronized (this) {
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
BufferedSubscription<T> pred = null, next;
|
||||
for (BufferedSubscription<T> b = clients; b != null; b = next) {
|
||||
next = b.next;
|
||||
@ -758,6 +790,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
pred = b;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return subs;
|
||||
}
|
||||
@ -771,8 +805,11 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
public boolean isSubscribed(Subscriber<? super T> subscriber) {
|
||||
if (subscriber == null) throw new NullPointerException();
|
||||
boolean subscribed = false;
|
||||
ReentrantLock lock = this.lock;
|
||||
if (!closed) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
BufferedSubscription<T> pred = null, next;
|
||||
for (BufferedSubscription<T> b = clients; b != null; b = next) {
|
||||
next = b.next;
|
||||
@ -783,14 +820,16 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
else
|
||||
pred.next = next;
|
||||
}
|
||||
else if (subscriber.equals(b.subscriber))
|
||||
return true;
|
||||
else if (subscribed = subscriber.equals(b.subscriber))
|
||||
break;
|
||||
else
|
||||
pred = b;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -803,7 +842,9 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
public long estimateMinimumDemand() {
|
||||
long min = Long.MAX_VALUE;
|
||||
boolean nonEmpty = false;
|
||||
synchronized (this) {
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
BufferedSubscription<T> pred = null, next;
|
||||
for (BufferedSubscription<T> b = clients; b != null; b = next) {
|
||||
int n; long d;
|
||||
@ -822,6 +863,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
pred = b;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return nonEmpty ? min : 0;
|
||||
}
|
||||
@ -834,7 +877,9 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
*/
|
||||
public int estimateMaximumLag() {
|
||||
int max = 0;
|
||||
synchronized (this) {
|
||||
ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
BufferedSubscription<T> pred = null, next;
|
||||
for (BufferedSubscription<T> b = clients; b != null; b = next) {
|
||||
int n;
|
||||
@ -852,6 +897,8 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
||||
pred = b;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@ -221,13 +221,18 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* simple feedback control mechanism that will slow down the rate that
|
||||
* new tasks are submitted.
|
||||
*
|
||||
* <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. This policy is designed only for
|
||||
* those rare cases in which task completion is never relied upon.
|
||||
*
|
||||
* <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.) This policy is rarely acceptable. In
|
||||
* nearly all cases, you should also cancel the task to cause an
|
||||
* exception in any component waiting for its completion, and/or log
|
||||
* the failure, as illustrated in {@link
|
||||
* ThreadPoolExecutor.DiscardOldestPolicy} documentation.
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
@ -272,7 +277,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*
|
||||
* </dl>
|
||||
*
|
||||
* <p><b>Extension example</b>. Most extensions of this class
|
||||
* <p><b>Extension example.</b> Most extensions of this class
|
||||
* override one or more of the protected hook methods. For example,
|
||||
* here is a subclass that adds a simple pause/resume feature:
|
||||
*
|
||||
@ -1149,8 +1154,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
|
||||
/**
|
||||
* Creates a new {@code ThreadPoolExecutor} with the given initial
|
||||
* parameters, the default thread factory and the default rejected
|
||||
* execution handler.
|
||||
* parameters, the
|
||||
* {@linkplain Executors#defaultThreadFactory default thread factory}
|
||||
* and the {@linkplain ThreadPoolExecutor.AbortPolicy
|
||||
* default rejected execution handler}.
|
||||
*
|
||||
* <p>It may be more convenient to use one of the {@link Executors}
|
||||
* factory methods instead of this general purpose constructor.
|
||||
@ -1184,7 +1191,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
|
||||
/**
|
||||
* Creates a new {@code ThreadPoolExecutor} with the given initial
|
||||
* parameters and {@linkplain ThreadPoolExecutor.AbortPolicy
|
||||
* parameters and the {@linkplain ThreadPoolExecutor.AbortPolicy
|
||||
* default rejected execution handler}.
|
||||
*
|
||||
* @param corePoolSize the number of threads to keep in the pool, even
|
||||
@ -1220,7 +1227,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
|
||||
/**
|
||||
* Creates a new {@code ThreadPoolExecutor} with the given initial
|
||||
* parameters and
|
||||
* parameters and the
|
||||
* {@linkplain Executors#defaultThreadFactory default thread factory}.
|
||||
*
|
||||
* @param corePoolSize the number of threads to keep in the pool, even
|
||||
@ -2081,7 +2088,20 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
/**
|
||||
* A handler for rejected tasks that discards the oldest unhandled
|
||||
* request and then retries {@code execute}, unless the executor
|
||||
* is shut down, in which case the task is discarded.
|
||||
* is shut down, in which case the task is discarded. This policy is
|
||||
* rarely useful in cases where other threads may be waiting for
|
||||
* tasks to terminate, or failures must be recorded. Instead consider
|
||||
* using a handler of the form:
|
||||
* <pre> {@code
|
||||
* new RejectedExecutionHandler() {
|
||||
* public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
|
||||
* Runnable dropped = e.getQueue().poll();
|
||||
* if (dropped instanceof Future<?>) {
|
||||
* ((Future<?>)dropped).cancel(false);
|
||||
* // also consider logging the failure
|
||||
* }
|
||||
* e.execute(r); // retry
|
||||
* }}}</pre>
|
||||
*/
|
||||
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
|
||||
/**
|
||||
|
||||
@ -68,9 +68,8 @@ public class AtomicBoolean implements java.io.Serializable {
|
||||
* @param initialValue the initial value
|
||||
*/
|
||||
public AtomicBoolean(boolean initialValue) {
|
||||
if (initialValue) {
|
||||
if (initialValue)
|
||||
value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -62,7 +62,7 @@ import java.lang.invoke.VarHandle;
|
||||
*
|
||||
* private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
|
||||
* AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
|
||||
* private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
|
||||
* private static final AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
|
||||
* AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
|
||||
*
|
||||
* Node getLeft() { return left; }
|
||||
|
||||
@ -111,16 +111,17 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
|
||||
|| ((r = doubleToRawLongBits
|
||||
(function.applyAsDouble(longBitsToDouble(b = base), x))) != b
|
||||
&& !casBase(b, r))) {
|
||||
int index = getProbe();
|
||||
boolean uncontended = true;
|
||||
if (cs == null
|
||||
|| (m = cs.length - 1) < 0
|
||||
|| (c = cs[getProbe() & m]) == null
|
||||
|| (c = cs[index & m]) == null
|
||||
|| !(uncontended =
|
||||
((r = doubleToRawLongBits
|
||||
(function.applyAsDouble
|
||||
(longBitsToDouble(v = c.value), x))) == v)
|
||||
|| c.cas(v, r)))
|
||||
doubleAccumulate(x, function, uncontended);
|
||||
doubleAccumulate(x, function, uncontended, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -92,13 +92,14 @@ public class DoubleAdder extends Striped64 implements Serializable {
|
||||
!casBase(b = base,
|
||||
Double.doubleToRawLongBits
|
||||
(Double.longBitsToDouble(b) + x))) {
|
||||
int index = getProbe();
|
||||
boolean uncontended = true;
|
||||
if (cs == null || (m = cs.length - 1) < 0 ||
|
||||
(c = cs[getProbe() & m]) == null ||
|
||||
(c = cs[index & m]) == null ||
|
||||
!(uncontended = c.cas(v = c.value,
|
||||
Double.doubleToRawLongBits
|
||||
(Double.longBitsToDouble(v) + x))))
|
||||
doubleAccumulate(x, null, uncontended);
|
||||
doubleAccumulate(x, null, uncontended, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -108,14 +108,15 @@ public class LongAccumulator extends Striped64 implements Serializable {
|
||||
if ((cs = cells) != null
|
||||
|| ((r = function.applyAsLong(b = base, x)) != b
|
||||
&& !casBase(b, r))) {
|
||||
int index = getProbe();
|
||||
boolean uncontended = true;
|
||||
if (cs == null
|
||||
|| (m = cs.length - 1) < 0
|
||||
|| (c = cs[getProbe() & m]) == null
|
||||
|| (c = cs[index & m]) == null
|
||||
|| !(uncontended =
|
||||
(r = function.applyAsLong(v = c.value, x)) == v
|
||||
|| c.cas(v, r)))
|
||||
longAccumulate(x, function, uncontended);
|
||||
longAccumulate(x, function, uncontended, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -85,11 +85,12 @@ public class LongAdder extends Striped64 implements Serializable {
|
||||
public void add(long x) {
|
||||
Cell[] cs; long b, v; int m; Cell c;
|
||||
if ((cs = cells) != null || !casBase(b = base, b + x)) {
|
||||
int index = getProbe();
|
||||
boolean uncontended = true;
|
||||
if (cs == null || (m = cs.length - 1) < 0 ||
|
||||
(c = cs[getProbe() & m]) == null ||
|
||||
(c = cs[index & m]) == null ||
|
||||
!(uncontended = c.cas(v = c.value, v + x)))
|
||||
longAccumulate(x, null, uncontended);
|
||||
longAccumulate(x, null, uncontended, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -125,7 +125,7 @@ abstract class Striped64 extends Number {
|
||||
volatile long value;
|
||||
Cell(long x) { value = x; }
|
||||
final boolean cas(long cmp, long val) {
|
||||
return VALUE.compareAndSet(this, cmp, val);
|
||||
return VALUE.weakCompareAndSetRelease(this, cmp, val);
|
||||
}
|
||||
final void reset() {
|
||||
VALUE.setVolatile(this, 0L);
|
||||
@ -178,7 +178,7 @@ abstract class Striped64 extends Number {
|
||||
* CASes the base field.
|
||||
*/
|
||||
final boolean casBase(long cmp, long val) {
|
||||
return BASE.compareAndSet(this, cmp, val);
|
||||
return BASE.weakCompareAndSetRelease(this, cmp, val);
|
||||
}
|
||||
|
||||
final long getAndSetBase(long val) {
|
||||
@ -224,20 +224,19 @@ abstract class Striped64 extends Number {
|
||||
* @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
|
||||
* @param index thread index from getProbe
|
||||
*/
|
||||
final void longAccumulate(long x, LongBinaryOperator fn,
|
||||
boolean wasUncontended) {
|
||||
int h;
|
||||
if ((h = getProbe()) == 0) {
|
||||
boolean wasUncontended, int index) {
|
||||
if (index == 0) {
|
||||
ThreadLocalRandom.current(); // force initialization
|
||||
h = getProbe();
|
||||
index = getProbe();
|
||||
wasUncontended = true;
|
||||
}
|
||||
boolean collide = false; // True if last slot nonempty
|
||||
done: for (;;) {
|
||||
for (boolean collide = false;;) { // True if last slot nonempty
|
||||
Cell[] cs; Cell c; int n; long v;
|
||||
if ((cs = cells) != null && (n = cs.length) > 0) {
|
||||
if ((c = cs[(n - 1) & h]) == null) {
|
||||
if ((c = cs[(n - 1) & index]) == null) {
|
||||
if (cellsBusy == 0) { // Try to attach new Cell
|
||||
Cell r = new Cell(x); // Optimistically create
|
||||
if (cellsBusy == 0 && casCellsBusy()) {
|
||||
@ -245,9 +244,9 @@ abstract class Striped64 extends Number {
|
||||
Cell[] rs; int m, j;
|
||||
if ((rs = cells) != null &&
|
||||
(m = rs.length) > 0 &&
|
||||
rs[j = (m - 1) & h] == null) {
|
||||
rs[j = (m - 1) & index] == null) {
|
||||
rs[j] = r;
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
cellsBusy = 0;
|
||||
@ -276,15 +275,15 @@ abstract class Striped64 extends Number {
|
||||
collide = false;
|
||||
continue; // Retry with expanded table
|
||||
}
|
||||
h = advanceProbe(h);
|
||||
index = advanceProbe(index);
|
||||
}
|
||||
else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
|
||||
try { // Initialize table
|
||||
if (cells == cs) {
|
||||
Cell[] rs = new Cell[2];
|
||||
rs[h & 1] = new Cell(x);
|
||||
rs[index & 1] = new Cell(x);
|
||||
cells = rs;
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
cellsBusy = 0;
|
||||
@ -293,7 +292,7 @@ abstract class Striped64 extends Number {
|
||||
// Fall back on using base
|
||||
else if (casBase(v = base,
|
||||
(fn == null) ? v + x : fn.applyAsLong(v, x)))
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,18 +309,16 @@ abstract class Striped64 extends Number {
|
||||
* maintained by copy/paste/adapt.
|
||||
*/
|
||||
final void doubleAccumulate(double x, DoubleBinaryOperator fn,
|
||||
boolean wasUncontended) {
|
||||
int h;
|
||||
if ((h = getProbe()) == 0) {
|
||||
boolean wasUncontended, int index) {
|
||||
if (index == 0) {
|
||||
ThreadLocalRandom.current(); // force initialization
|
||||
h = getProbe();
|
||||
index = getProbe();
|
||||
wasUncontended = true;
|
||||
}
|
||||
boolean collide = false; // True if last slot nonempty
|
||||
done: for (;;) {
|
||||
for (boolean collide = false;;) { // True if last slot nonempty
|
||||
Cell[] cs; Cell c; int n; long v;
|
||||
if ((cs = cells) != null && (n = cs.length) > 0) {
|
||||
if ((c = cs[(n - 1) & h]) == null) {
|
||||
if ((c = cs[(n - 1) & index]) == null) {
|
||||
if (cellsBusy == 0) { // Try to attach new Cell
|
||||
Cell r = new Cell(Double.doubleToRawLongBits(x));
|
||||
if (cellsBusy == 0 && casCellsBusy()) {
|
||||
@ -329,9 +326,9 @@ abstract class Striped64 extends Number {
|
||||
Cell[] rs; int m, j;
|
||||
if ((rs = cells) != null &&
|
||||
(m = rs.length) > 0 &&
|
||||
rs[j = (m - 1) & h] == null) {
|
||||
rs[j = (m - 1) & index] == null) {
|
||||
rs[j] = r;
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
cellsBusy = 0;
|
||||
@ -359,15 +356,15 @@ abstract class Striped64 extends Number {
|
||||
collide = false;
|
||||
continue; // Retry with expanded table
|
||||
}
|
||||
h = advanceProbe(h);
|
||||
index = advanceProbe(index);
|
||||
}
|
||||
else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
|
||||
try { // Initialize table
|
||||
if (cells == cs) {
|
||||
Cell[] rs = new Cell[2];
|
||||
rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
|
||||
rs[index & 1] = new Cell(Double.doubleToRawLongBits(x));
|
||||
cells = rs;
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
cellsBusy = 0;
|
||||
@ -375,7 +372,7 @@ abstract class Striped64 extends Number {
|
||||
}
|
||||
// Fall back on using base
|
||||
else if (casBase(v = base, apply(fn, v, x)))
|
||||
break done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
* <pre> {@code
|
||||
* class Sequencer {
|
||||
* private final AtomicLong sequenceNumber
|
||||
* = new AtomicLong(0);
|
||||
* = new AtomicLong(17);
|
||||
* public long next() {
|
||||
* return sequenceNumber.getAndIncrement();
|
||||
* }
|
||||
|
||||
@ -137,13 +137,13 @@ import jdk.internal.misc.Unsafe;
|
||||
* of exclusive synchronization takes the form:
|
||||
*
|
||||
* <pre>
|
||||
* Acquire:
|
||||
* <em>Acquire:</em>
|
||||
* while (!tryAcquire(arg)) {
|
||||
* <em>enqueue thread if it is not already queued</em>;
|
||||
* <em>possibly block current thread</em>;
|
||||
* }
|
||||
*
|
||||
* Release:
|
||||
* <em>Release:</em>
|
||||
* if (tryRelease(arg))
|
||||
* <em>unblock the first queued thread</em>;
|
||||
* </pre>
|
||||
|
||||
@ -550,7 +550,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
*
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* final ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
* public void m() {
|
||||
* assert lock.getHoldCount() == 0;
|
||||
@ -580,7 +580,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
*
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* final ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
*
|
||||
* public void m() {
|
||||
@ -594,7 +594,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
*
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* final ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
*
|
||||
* public void m() {
|
||||
|
||||
@ -128,7 +128,7 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* locks: a deserialized lock is in the unlocked state, regardless of
|
||||
* its state when serialized.
|
||||
*
|
||||
* <p><b>Sample usages</b>. Here is a code sketch showing how to perform
|
||||
* <p><b>Sample usages.</b> Here is a code sketch showing how to perform
|
||||
* lock downgrading after updating a cache (exception handling is
|
||||
* particularly tricky when handling multiple locks in a non-nested
|
||||
* fashion):
|
||||
@ -149,7 +149,7 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* // Recheck state because another thread might have
|
||||
* // acquired write lock and changed state before we did.
|
||||
* if (!cacheValid) {
|
||||
* data = ...
|
||||
* data = ...;
|
||||
* cacheValid = true;
|
||||
* }
|
||||
* // Downgrade by acquiring read lock before releasing write lock
|
||||
|
||||
@ -212,8 +212,8 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Upgrade read lock to write lock
|
||||
* void moveIfAtOrigin(double newX, double newY) {
|
||||
* // upgrade read lock to write lock
|
||||
* void moveIfAtOrigin2(double newX, double newY) {
|
||||
* long stamp = sl.readLock();
|
||||
* try {
|
||||
* while (x == 0.0 && y == 0.0) {
|
||||
|
||||
@ -360,7 +360,6 @@ public class IteratorMicroBenchmark {
|
||||
}
|
||||
|
||||
Stream<Job> jobs(Collection<Integer> x) {
|
||||
final String klazz = goodClassName(x);
|
||||
return concatStreams(
|
||||
collectionJobs(x),
|
||||
|
||||
|
||||
@ -84,9 +84,16 @@ public class Invoke {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
testInvokeAll();
|
||||
testInvokeAny();
|
||||
testInvokeAny_cancellationInterrupt();
|
||||
for (int nThreads = 1; nThreads <= 6; ++nThreads) {
|
||||
// untimed
|
||||
testInvokeAll(nThreads, false);
|
||||
testInvokeAny(nThreads, false);
|
||||
testInvokeAny_cancellationInterrupt(nThreads, false);
|
||||
// timed
|
||||
testInvokeAll(nThreads, true);
|
||||
testInvokeAny(nThreads, true);
|
||||
testInvokeAny_cancellationInterrupt(nThreads, true);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
if (failed > 0)
|
||||
@ -96,10 +103,8 @@ public class Invoke {
|
||||
|
||||
static final long timeoutSeconds = 10L;
|
||||
|
||||
static void testInvokeAll() throws Throwable {
|
||||
static void testInvokeAll(int nThreads, boolean timed) throws Throwable {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
final int nThreads = rnd.nextInt(2, 7);
|
||||
final boolean timed = rnd.nextBoolean();
|
||||
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
|
||||
final AtomicLong count = new AtomicLong(0);
|
||||
class Task implements Callable<Long> {
|
||||
@ -136,17 +141,15 @@ public class Invoke {
|
||||
}
|
||||
}
|
||||
|
||||
static void testInvokeAny() throws Throwable {
|
||||
static void testInvokeAny(int nThreads, boolean timed) throws Throwable {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
final boolean timed = rnd.nextBoolean();
|
||||
final ExecutorService pool = Executors.newSingleThreadExecutor();
|
||||
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
|
||||
final AtomicLong count = new AtomicLong(0);
|
||||
final CountDownLatch invokeAnyDone = new CountDownLatch(1);
|
||||
class Task implements Callable<Long> {
|
||||
public Long call() throws Exception {
|
||||
long x = count.incrementAndGet();
|
||||
check(x <= 2);
|
||||
if (x == 2) {
|
||||
if (x > 1) {
|
||||
// wait for main thread to interrupt us ...
|
||||
awaitInterrupt(timeoutSeconds);
|
||||
// ... and then for invokeAny to return
|
||||
@ -173,12 +176,12 @@ public class Invoke {
|
||||
check(val == 1);
|
||||
invokeAnyDone.countDown();
|
||||
|
||||
// inherent race between main thread interrupt and
|
||||
// start of second task
|
||||
check(count.get() == 1 || count.get() == 2);
|
||||
|
||||
pool.shutdown();
|
||||
check(pool.awaitTermination(timeoutSeconds, SECONDS));
|
||||
|
||||
long c = count.get();
|
||||
check(c >= 1 && c <= tasks.size());
|
||||
|
||||
} finally {
|
||||
pool.shutdownNow();
|
||||
}
|
||||
@ -187,18 +190,16 @@ public class Invoke {
|
||||
/**
|
||||
* Every remaining running task is sent an interrupt for cancellation.
|
||||
*/
|
||||
static void testInvokeAny_cancellationInterrupt() throws Throwable {
|
||||
static void testInvokeAny_cancellationInterrupt(int nThreads, boolean timed) throws Throwable {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
final int nThreads = rnd.nextInt(2, 7);
|
||||
final boolean timed = rnd.nextBoolean();
|
||||
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
|
||||
final AtomicLong count = new AtomicLong(0);
|
||||
final AtomicLong interruptedCount = new AtomicLong(0);
|
||||
final CyclicBarrier allStarted = new CyclicBarrier(nThreads);
|
||||
class Task implements Callable<Long> {
|
||||
public Long call() throws Exception {
|
||||
allStarted.await();
|
||||
long x = count.incrementAndGet();
|
||||
allStarted.await();
|
||||
if (x > 1)
|
||||
// main thread will interrupt us
|
||||
awaitInterrupt(timeoutSeconds);
|
||||
|
||||
@ -715,7 +715,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase {
|
||||
Integer x = (Integer) it.next();
|
||||
assertEquals(s + i, (int) x);
|
||||
for (Object[] a : as)
|
||||
assertSame(a1[i], x);
|
||||
assertSame(a[i], x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -738,7 +738,7 @@ public class ArrayDequeTest extends JSR166TestCase {
|
||||
Integer x = (Integer) it.next();
|
||||
assertEquals(s + i, (int) x);
|
||||
for (Object[] a : as)
|
||||
assertSame(a1[i], x);
|
||||
assertSame(a[i], x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ public class ArrayListTest extends JSR166TestCase {
|
||||
}
|
||||
}
|
||||
return newTestSuite(
|
||||
// ArrayListTest.class,
|
||||
ArrayListTest.class,
|
||||
CollectionTest.testSuite(new Implementation()),
|
||||
CollectionTest.testSuite(new SubListImplementation()));
|
||||
}
|
||||
|
||||
@ -440,7 +440,6 @@ public class Collection8Test extends JSR166TestCase {
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
it.next();
|
||||
}
|
||||
Consumer alwaysThrows = e -> { throw new AssertionError(); };
|
||||
// TODO: many more removal methods
|
||||
if (rnd.nextBoolean()) {
|
||||
for (Iterator z = c.iterator(); z.hasNext(); ) {
|
||||
@ -661,7 +660,6 @@ public class Collection8Test extends JSR166TestCase {
|
||||
*/
|
||||
public void testStreamForEach() 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();
|
||||
@ -719,7 +717,6 @@ public class Collection8Test extends JSR166TestCase {
|
||||
*/
|
||||
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();
|
||||
|
||||
@ -3778,16 +3778,6 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
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.
|
||||
@ -4217,12 +4207,9 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
// 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;
|
||||
if (type == boolean.class) args[i] = false;
|
||||
else if (type == int.class) args[i] = 0;
|
||||
else if (type == long.class) args[i] = 0L;
|
||||
}
|
||||
for (CompletionStage<Integer> stage : stages) {
|
||||
try {
|
||||
|
||||
@ -1010,7 +1010,6 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
|
||||
* ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=ConcurrentLinkedDequeTest -Djsr166.methodFilter=testBug8189387 tck
|
||||
*/
|
||||
public void testBug8189387() {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
Object x = new Object();
|
||||
for (int n = expensiveTests ? 100_000 : 10; n--> 0; ) {
|
||||
ConcurrentLinkedDeque<Object> d = new ConcurrentLinkedDeque<>();
|
||||
|
||||
@ -90,7 +90,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testNewCachedThreadPool3() {
|
||||
try {
|
||||
ExecutorService e = Executors.newCachedThreadPool(null);
|
||||
ExecutorService unused = Executors.newCachedThreadPool(null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -124,7 +124,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testNewSingleThreadExecutor3() {
|
||||
try {
|
||||
ExecutorService e = Executors.newSingleThreadExecutor(null);
|
||||
ExecutorService unused = Executors.newSingleThreadExecutor(null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -172,7 +172,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testNewFixedThreadPool3() {
|
||||
try {
|
||||
ExecutorService e = Executors.newFixedThreadPool(2, null);
|
||||
ExecutorService unused = Executors.newFixedThreadPool(2, null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -182,7 +182,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testNewFixedThreadPool4() {
|
||||
try {
|
||||
ExecutorService e = Executors.newFixedThreadPool(0);
|
||||
ExecutorService unused = Executors.newFixedThreadPool(0);
|
||||
shouldThrow();
|
||||
} catch (IllegalArgumentException success) {}
|
||||
}
|
||||
@ -204,7 +204,8 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testUnconfigurableExecutorServiceNPE() {
|
||||
try {
|
||||
ExecutorService e = Executors.unconfigurableExecutorService(null);
|
||||
ExecutorService unused =
|
||||
Executors.unconfigurableExecutorService(null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -214,7 +215,8 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testUnconfigurableScheduledExecutorServiceNPE() {
|
||||
try {
|
||||
ExecutorService e = Executors.unconfigurableScheduledExecutorService(null);
|
||||
ExecutorService unused =
|
||||
Executors.unconfigurableScheduledExecutorService(null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -304,9 +306,11 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
Executors.newScheduledThreadPool(2),
|
||||
};
|
||||
|
||||
final Runnable sleeper = new CheckedInterruptedRunnable() {
|
||||
final CountDownLatch done = new CountDownLatch(1);
|
||||
|
||||
final Runnable sleeper = new CheckedRunnable() {
|
||||
public void realRun() throws InterruptedException {
|
||||
delay(LONG_DELAY_MS);
|
||||
done.await(LONG_DELAY_MS, MILLISECONDS);
|
||||
}};
|
||||
|
||||
List<Thread> threads = new ArrayList<>();
|
||||
@ -319,6 +323,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
}
|
||||
for (Thread thread : threads)
|
||||
awaitTermination(thread);
|
||||
done.countDown();
|
||||
for (ExecutorService executor : executors)
|
||||
joinPool(executor);
|
||||
}
|
||||
@ -578,7 +583,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testCallableNPE1() {
|
||||
try {
|
||||
Callable c = Executors.callable((Runnable) null);
|
||||
Callable unused = Executors.callable((Runnable) null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -588,7 +593,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testCallableNPE2() {
|
||||
try {
|
||||
Callable c = Executors.callable((Runnable) null, one);
|
||||
Callable unused = Executors.callable((Runnable) null, one);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -598,7 +603,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testCallableNPE3() {
|
||||
try {
|
||||
Callable c = Executors.callable((PrivilegedAction) null);
|
||||
Callable unused = Executors.callable((PrivilegedAction) null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -608,7 +613,7 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testCallableNPE4() {
|
||||
try {
|
||||
Callable c = Executors.callable((PrivilegedExceptionAction) null);
|
||||
Callable unused = Executors.callable((PrivilegedExceptionAction) null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
|
||||
@ -375,7 +375,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
|
||||
p.shutdown();
|
||||
assertTrue(p.isShutdown());
|
||||
try {
|
||||
ForkJoinTask<Integer> f = p.submit(new FibTask(8));
|
||||
ForkJoinTask<Integer> unused = p.submit(new FibTask(8));
|
||||
shouldThrow();
|
||||
} catch (RejectedExecutionException success) {}
|
||||
}
|
||||
@ -563,7 +563,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
|
||||
ExecutorService e = new ForkJoinPool(1);
|
||||
try (PoolCleaner cleaner = cleaner(e)) {
|
||||
try {
|
||||
Future<?> future = e.submit((Runnable) null);
|
||||
Future<?> unused = e.submit((Runnable) null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
@ -576,7 +576,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
|
||||
ExecutorService e = new ForkJoinPool(1);
|
||||
try (PoolCleaner cleaner = cleaner(e)) {
|
||||
try {
|
||||
Future<String> future = e.submit((Callable) null);
|
||||
Future<String> unused = e.submit((Callable) null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
|
||||
@ -1227,8 +1227,9 @@ public class JSR166TestCase extends TestCase {
|
||||
} catch (TimeoutException success) {
|
||||
} catch (Exception fail) {
|
||||
threadUnexpectedException(fail);
|
||||
} finally { future.cancel(true); }
|
||||
}
|
||||
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
|
||||
assertFalse(future.isDone());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -408,7 +408,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
FailingFibTask f = new FailingFibTask(8);
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.join();
|
||||
f.join();
|
||||
shouldThrow();
|
||||
} catch (FJException success) {
|
||||
checkCompletedAbnormally(f, success);
|
||||
@ -427,7 +427,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
FailingFibTask f = new FailingFibTask(8);
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.get();
|
||||
f.get();
|
||||
shouldThrow();
|
||||
} catch (ExecutionException success) {
|
||||
Throwable cause = success.getCause();
|
||||
@ -448,7 +448,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
FailingFibTask f = new FailingFibTask(8);
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.get(LONG_DELAY_MS, MILLISECONDS);
|
||||
f.get(LONG_DELAY_MS, MILLISECONDS);
|
||||
shouldThrow();
|
||||
} catch (ExecutionException success) {
|
||||
Throwable cause = success.getCause();
|
||||
@ -485,7 +485,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
FibTask f = new FibTask(8);
|
||||
assertTrue(f.cancel(true));
|
||||
try {
|
||||
Integer r = f.invoke();
|
||||
f.invoke();
|
||||
shouldThrow();
|
||||
} catch (CancellationException success) {
|
||||
checkCancelled(f);
|
||||
@ -505,7 +505,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
assertTrue(f.cancel(true));
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.join();
|
||||
f.join();
|
||||
shouldThrow();
|
||||
} catch (CancellationException success) {
|
||||
checkCancelled(f);
|
||||
@ -525,7 +525,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
assertTrue(f.cancel(true));
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.get();
|
||||
f.get();
|
||||
shouldThrow();
|
||||
} catch (CancellationException success) {
|
||||
checkCancelled(f);
|
||||
@ -545,7 +545,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
assertTrue(f.cancel(true));
|
||||
assertSame(f, f.fork());
|
||||
try {
|
||||
Integer r = f.get(LONG_DELAY_MS, MILLISECONDS);
|
||||
f.get(LONG_DELAY_MS, MILLISECONDS);
|
||||
shouldThrow();
|
||||
} catch (CancellationException success) {
|
||||
checkCancelled(f);
|
||||
@ -689,7 +689,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
||||
FibTask f = new FibTask(8);
|
||||
f.completeExceptionally(new FJException());
|
||||
try {
|
||||
Integer r = f.invoke();
|
||||
f.invoke();
|
||||
shouldThrow();
|
||||
} catch (FJException success) {
|
||||
checkCompletedAbnormally(f, success);
|
||||
|
||||
@ -39,6 +39,9 @@ import java.util.concurrent.atomic.LongAdder;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
@ -357,12 +360,12 @@ public class SplittableRandomTest extends JSR166TestCase {
|
||||
SplittableRandom r = new SplittableRandom();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> { java.util.stream.IntStream x = r.ints(-1L); },
|
||||
() -> { java.util.stream.IntStream x = r.ints(-1L, 2, 3); },
|
||||
() -> { java.util.stream.LongStream x = r.longs(-1L); },
|
||||
() -> { java.util.stream.LongStream x = r.longs(-1L, -1L, 1L); },
|
||||
() -> { java.util.stream.DoubleStream x = r.doubles(-1L); },
|
||||
() -> { java.util.stream.DoubleStream x = r.doubles(-1L, .5, .6); });
|
||||
() -> { IntStream unused = r.ints(-1L); },
|
||||
() -> { IntStream unused = r.ints(-1L, 2, 3); },
|
||||
() -> { LongStream unused = r.longs(-1L); },
|
||||
() -> { LongStream unused = r.longs(-1L, -1L, 1L); },
|
||||
() -> { DoubleStream unused = r.doubles(-1L); },
|
||||
() -> { DoubleStream unused = r.doubles(-1L, .5, .6); });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,12 +376,12 @@ public class SplittableRandomTest extends JSR166TestCase {
|
||||
SplittableRandom r = new SplittableRandom();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> { java.util.stream.IntStream x = r.ints(2, 1); },
|
||||
() -> { java.util.stream.IntStream x = r.ints(10, 42, 42); },
|
||||
() -> { java.util.stream.LongStream x = r.longs(-1L, -1L); },
|
||||
() -> { java.util.stream.LongStream x = r.longs(10, 1L, -2L); },
|
||||
() -> { java.util.stream.DoubleStream x = r.doubles(0.0, 0.0); },
|
||||
() -> { java.util.stream.DoubleStream x = r.doubles(10, .5, .4); });
|
||||
() -> { IntStream unused = r.ints(2, 1); },
|
||||
() -> { IntStream unused = r.ints(10, 42, 42); },
|
||||
() -> { LongStream unused = r.longs(-1L, -1L); },
|
||||
() -> { LongStream unused = r.longs(10, 1L, -2L); },
|
||||
() -> { DoubleStream unused = r.doubles(0.0, 0.0); },
|
||||
() -> { DoubleStream unused = r.doubles(10, .5, .4); });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -370,7 +370,7 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
|
||||
final StampedLock lock = new StampedLock();
|
||||
long s = lock.writeLock();
|
||||
long stamp = lock.writeLock();
|
||||
|
||||
Action[] interruptibleLockBlockingActions = {
|
||||
() -> lock.writeLockInterruptibly(),
|
||||
@ -385,6 +385,8 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
shuffle(interruptibleLockBlockingActions);
|
||||
|
||||
assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
|
||||
|
||||
releaseWriteLock(lock, stamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,7 +394,7 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
|
||||
final StampedLock lock = new StampedLock();
|
||||
long s = lock.readLock();
|
||||
long stamp = lock.readLock();
|
||||
|
||||
Action[] interruptibleLockBlockingActions = {
|
||||
() -> lock.writeLockInterruptibly(),
|
||||
@ -403,6 +405,8 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
shuffle(interruptibleLockBlockingActions);
|
||||
|
||||
assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
|
||||
|
||||
releaseReadLock(lock, stamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -726,6 +730,7 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
lock.unlockWrite(s);
|
||||
s = lock.readLock();
|
||||
assertTrue(lock.toString().contains("Read-locks"));
|
||||
releaseReadLock(lock, s);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -985,7 +985,7 @@ public class SubmissionPublisherTest extends JSR166TestCase {
|
||||
public void testConsumeNPE() {
|
||||
SubmissionPublisher<Integer> p = basicPublisher();
|
||||
try {
|
||||
CompletableFuture<Void> f = p.consume(null);
|
||||
CompletableFuture<Void> unused = p.consume(null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
|
||||
@ -464,7 +464,7 @@ public class SynchronousQueueTest extends JSR166TestCase {
|
||||
public void testToArray_null(boolean fair) {
|
||||
final SynchronousQueue q = new SynchronousQueue(fair);
|
||||
try {
|
||||
Object[] o = q.toArray((Object[])null);
|
||||
Object[] unused = q.toArray((Object[])null);
|
||||
shouldThrow();
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
|
||||
@ -384,27 +384,24 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
|
||||
new AtomicReference<>();
|
||||
final AtomicLong rand = new AtomicLong();
|
||||
|
||||
long firstRand = 0;
|
||||
ThreadLocalRandom firstThreadLocalRandom = null;
|
||||
|
||||
Runnable getRandomState = new CheckedRunnable() {
|
||||
public void realRun() {
|
||||
ThreadLocalRandom current = ThreadLocalRandom.current();
|
||||
assertSame(current, ThreadLocalRandom.current());
|
||||
// test bug: the following is not guaranteed and not true in JDK8
|
||||
// assertNotSame(current, threadLocalRandom.get());
|
||||
rand.set(current.nextLong());
|
||||
threadLocalRandom.set(current);
|
||||
}};
|
||||
|
||||
Thread first = newStartedThread(getRandomState);
|
||||
awaitTermination(first);
|
||||
firstRand = rand.get();
|
||||
firstThreadLocalRandom = threadLocalRandom.get();
|
||||
awaitTermination(newStartedThread(getRandomState));
|
||||
long firstRand = rand.get();
|
||||
ThreadLocalRandom firstThreadLocalRandom = threadLocalRandom.get();
|
||||
assertNotNull(firstThreadLocalRandom);
|
||||
|
||||
for (int i = 0; i < NCALLS; i++) {
|
||||
Thread t = newStartedThread(getRandomState);
|
||||
awaitTermination(t);
|
||||
awaitTermination(newStartedThread(getRandomState));
|
||||
if (testImplementationDetails)
|
||||
// ThreadLocalRandom has been a singleton since jdk8.
|
||||
assertSame(firstThreadLocalRandom, threadLocalRandom.get());
|
||||
if (firstRand != rand.get())
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user