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:
Martin Buchholz 2021-01-09 21:59:27 +00:00
parent 63e3bd7613
commit 270014ab4e
41 changed files with 273 additions and 207 deletions

View file

@ -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);

View file

@ -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

View file

@ -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() { ... }

View file

@ -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>
*

View file

@ -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 ...}
* }
* }
*

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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];

View file

@ -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() {

View file

@ -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;
}

View file

@ -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 {
/**

View file

@ -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;
}
}
/**

View file

@ -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; }

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -54,7 +54,7 @@
* <pre> {@code
* class Sequencer {
* private final AtomicLong sequenceNumber
* = new AtomicLong(0);
* = new AtomicLong(17);
* public long next() {
* return sequenceNumber.getAndIncrement();
* }

View file

@ -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>

View file

@ -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() {

View file

@ -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

View file

@ -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) {