下面列出了java.util.concurrent.atomic.AtomicReferenceFieldUpdater#get() 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* There are some scenarios where a completion {@link TerminalNotification} can be overridden with an error if
* errors are produced asynchronously.
* <p>
* This method helps set {@link TerminalNotification} atomically providing such an override.
*
* @param toSet {@link TerminalNotification} to set.
* @param overrideComplete Whether exisiting {@link TerminalNotification#complete()} should be overridden with the
* {@code toSet}.
* @param terminalNotificationUpdater {@link AtomicReferenceFieldUpdater} to access the current
* {@link TerminalNotification}.
* @param flagOwner instance of {@link R} that owns the current {@link TerminalNotification} field referenced by
* {@code terminalNotificationUpdater}.
* @param <R> Type of {@code flagOwner}.
* @return {@code true} if {@code toSet} is updated as the current {@link TerminalNotification}.
*/
public static <R> boolean trySetTerminal(TerminalNotification toSet, boolean overrideComplete,
AtomicReferenceFieldUpdater<R, TerminalNotification> terminalNotificationUpdater, R flagOwner) {
for (;;) {
TerminalNotification curr = terminalNotificationUpdater.get(flagOwner);
if (curr != null && !overrideComplete) {
// Once terminated, terminalNotification will never be set back to null.
return false;
} else if (curr == null && terminalNotificationUpdater.compareAndSet(flagOwner, null, toSet)) {
return true;
} else if (curr != null && curr.cause() == null) {
// Override complete
if (terminalNotificationUpdater.compareAndSet(flagOwner, curr, toSet)) {
return true;
}
} else {
return false;
}
}
}
/**
* Atomically set the field to a {@link Disposable} and dispose the old content.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the new Disposable to set
* @return true if successful, false if the field contains the {@link #DISPOSED} instance.
*/
static <T> boolean set(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) {
for (;;) {
Disposable current = updater.get(holder);
if (current == DISPOSED) {
if (newValue != null) {
newValue.dispose();
}
return false;
}
if (updater.compareAndSet(holder, current, newValue)) {
if (current != null) {
current.dispose();
}
return true;
}
}
}
/**
* Atomically set the field to a {@link Disposable} and dispose the old content.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the new Disposable to set
* @return true if successful, false if the field contains the {@link #DISPOSED} instance.
*/
public static <T> boolean set(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) {
for (;;) {
Disposable current = updater.get(holder);
if (current == DISPOSED) {
if (newValue != null) {
newValue.dispose();
}
return false;
}
if (updater.compareAndSet(holder, current, newValue)) {
if (current != null) {
current.dispose();
}
return true;
}
}
}
/**
* A generic utility to atomically replace a subscription or cancel the replacement
* if current subscription is marked as cancelled (as in {@link #cancelledSubscription()})
* or was concurrently updated before.
* <p>
* The replaced subscription is itself cancelled.
*
* @param field The Atomic container
* @param instance the instance reference
* @param s the subscription
* @param <F> the instance type
*
* @return true if replaced
*/
public static <F> boolean set(AtomicReferenceFieldUpdater<F, Subscription> field,
F instance,
Subscription s) {
for (; ; ) {
Subscription a = field.get(instance);
if (a == CancelledSubscription.INSTANCE) {
s.cancel();
return false;
}
if (field.compareAndSet(instance, a, s)) {
if (a != null) {
a.cancel();
}
return true;
}
}
}
static <T> boolean removeSequence(final T holder,
final AtomicReferenceFieldUpdater<T, Sequence[]> sequenceUpdater,
final Sequence sequence) {
int numToRemove;
Sequence[] oldSequences;
Sequence[] newSequences;
do {
oldSequences = sequenceUpdater.get(holder);
numToRemove = countMatching(oldSequences, sequence);
if (0 == numToRemove) {
break;
}
final int oldSize = oldSequences.length;
newSequences = new Sequence[oldSize - numToRemove];
for (int i = 0, pos = 0; i < oldSize; i++) {
final Sequence testSequence = oldSequences[i];
if (sequence != testSequence) {
newSequences[pos++] = testSequence;
}
}
} while (!sequenceUpdater.compareAndSet(holder, oldSequences, newSequences));
return numToRemove != 0;
}
/**
* Object arguments for parameters of type T that are not
* instances of the class passed to the newUpdater call will
* result in a ClassCastException being thrown.
*/
public void testFieldUpdaters_ClassCastException() {
// Use raw types to allow passing wrong object type, provoking CCE
final AtomicLongFieldUpdater longUpdater = aLongFieldUpdater();
final AtomicIntegerFieldUpdater intUpdater = anIntFieldUpdater();
final AtomicReferenceFieldUpdater refUpdater = anIntegerFieldUpdater();
final Object obj = new Object();
for (Object x : new Object[]{ new Object(), null }) {
Runnable[] throwingActions = {
() -> longUpdater.get(x),
() -> intUpdater.get(x),
() -> refUpdater.get(x),
() -> longUpdater.set(x, 17L),
() -> intUpdater.set(x, 17),
() -> refUpdater.set(x, (Integer) 17),
() -> longUpdater.addAndGet(x, 17L),
() -> intUpdater.addAndGet(x, 17),
() -> longUpdater.getAndUpdate(x, y -> y),
() -> intUpdater.getAndUpdate(x, y -> y),
() -> refUpdater.getAndUpdate(x, y -> y),
() -> longUpdater.compareAndSet(x, 17L, 42L),
() -> intUpdater.compareAndSet(x, 17, 42),
() -> refUpdater.compareAndSet(x, (Integer) 17, (Integer) 42),
};
assertThrows(ClassCastException.class, throwingActions);
}
}
/**
* 原子移除某个指定的sequence
*
* @param holder 原子更新的域所属的类对象
* @param sequenceUpdater 原子更新的域对象
* @param sequence 要移除的sequence
* @param <T>
* @return
*/
public static <T> boolean removeSequence(
final T holder,
final AtomicReferenceFieldUpdater<T, Sequence[]> sequenceUpdater,
final Sequence sequence)
{
int numToRemove;
Sequence[] oldSequences;
Sequence[] newSequences;
do
{
oldSequences = sequenceUpdater.get(holder);
numToRemove = countMatching(oldSequences, sequence);
if (0 == numToRemove)
{
break;
}
final int oldSize = oldSequences.length;
newSequences = new Sequence[oldSize - numToRemove];
for (int i = 0, pos = 0; i < oldSize; i++)
{
final Sequence testSequence = oldSequences[i];
if (sequence != testSequence)
{
newSequences[pos++] = testSequence;
}
}
}
while (!sequenceUpdater.compareAndSet(holder, oldSequences, newSequences));
return numToRemove != 0;
}
/**
* Atomically replace the {@link Disposable} in the field with the given new Disposable
* but do not dispose the old one.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the new Disposable to set, null allowed
* @return true if the operation succeeded, false if the target field contained
* the common {@link #DISPOSED} instance and the given disposable is not null but is disposed.
*/
static <T> boolean replace(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) {
for (;;) {
Disposable current = updater.get(holder);
if (current == DISPOSED) {
if (newValue != null) {
newValue.dispose();
}
return false;
}
if (updater.compareAndSet(holder, current, newValue)) {
return true;
}
}
}
/**
* Atomically dispose the {@link Disposable} in the field if not already disposed.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @return true if the {@link Disposable} held by the field was properly disposed
*/
static <T> boolean dispose(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder) {
Disposable current = updater.get(holder);
Disposable d = DISPOSED;
if (current != d) {
current = updater.getAndSet(holder, d);
if (current != d) {
if (current != null) {
current.dispose();
}
return true;
}
}
return false;
}
/**
* Atomically set the field to the given non-null {@link Disposable} and return true,
* or return false if the field is non-null.
* If the target field contains the common {@link #DISPOSED} instance, the supplied disposable
* is disposed. If the field contains other non-null {@link Disposable}, an {@link IllegalStateException}
* is signalled to the {@code errorCallback}.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the new Disposable to set, not null
* @return true if the operation succeeded, false
*/
public static <T> boolean setOnce(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, Disposable newValue,
Consumer<RuntimeException> errorCallback) {
Objects.requireNonNull(newValue, "newValue is null");
if (!updater.compareAndSet(holder, null, newValue)) {
newValue.dispose();
if (updater.get(holder) != DISPOSED) {
errorCallback.accept(new IllegalStateException("Disposable already pushed"));
}
return false;
}
return true;
}
/**
* Atomically replace the {@link Disposable} in the field with the given new Disposable
* but do not dispose the old one.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the new Disposable to set, null allowed
* @return true if the operation succeeded, false if the target field contained
* the common {@link #DISPOSED} instance and the given disposable is not null but is disposed.
*/
public static <T> boolean replace(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) {
for (;;) {
Disposable current = updater.get(holder);
if (current == DISPOSED) {
if (newValue != null) {
newValue.dispose();
}
return false;
}
if (updater.compareAndSet(holder, current, newValue)) {
return true;
}
}
}
/**
* Atomically dispose the {@link Disposable} in the field if not already disposed.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @return true if the {@link Disposable} held by the field was properly disposed
*/
public static <T> boolean dispose(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder) {
Disposable current = updater.get(holder);
Disposable d = DISPOSED;
if (current != d) {
current = updater.getAndSet(holder, d);
if (current != d) {
if (current != null) {
current.dispose();
}
return true;
}
}
return false;
}
/**
* Atomically try to set the given {@link Disposable} on the field if it is null or
* disposes it if the field contains {@link #DISPOSED}.
*
* @param updater the target field updater
* @param holder the target instance holding the field
* @param newValue the disposable to set
* @return true if successful, false otherwise
*/
public static <T> boolean trySet(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, Disposable newValue) {
if (!updater.compareAndSet(holder, null, newValue)) {
if (updater.get(holder) == DISPOSED) {
newValue.dispose();
}
return false;
}
return true;
}
private void mutateAdditionalResponseHeaders(
AtomicReferenceFieldUpdater<DefaultServiceRequestContext, HttpHeaders> atomicUpdater,
Consumer<HttpHeadersBuilder> mutator) {
for (;;) {
final HttpHeaders oldValue = atomicUpdater.get(this);
final HttpHeadersBuilder builder = oldValue.toBuilder();
mutator.accept(builder);
final HttpHeaders newValue = builder.build();
if (atomicUpdater.compareAndSet(this, oldValue, newValue)) {
return;
}
}
}
static <T> boolean removeSequence(final T holder,
final AtomicReferenceFieldUpdater<T, Sequence[]> sequenceUpdater,
final Sequence sequence) {
int numToRemove;
Sequence[] oldSequences;
Sequence[] newSequences;
do {
oldSequences = sequenceUpdater.get(holder);
numToRemove = countMatching(oldSequences, sequence);
if (0 == numToRemove) {
break;
}
final int oldSize = oldSequences.length;
newSequences = new Sequence[oldSize - numToRemove];
for (int i = 0, pos = 0; i < oldSize; i++) {
final Sequence testSequence = oldSequences[i];
if (sequence != testSequence) {
newSequences[pos++] = testSequence;
}
}
}
while (!sequenceUpdater.compareAndSet(holder, oldSequences, newSequences));
return numToRemove != 0;
}
/**
* A generic utility to atomically replace a subscription or cancel the replacement
* if the current subscription is marked as already cancelled (as in
* {@link #cancelledSubscription()}).
*
* @param field The Atomic container
* @param instance the instance reference
* @param s the subscription
* @param <F> the instance type
*
* @return true if replaced
*/
public static <F> boolean replace(AtomicReferenceFieldUpdater<F, Subscription> field,
F instance,
Subscription s) {
for (; ; ) {
Subscription a = field.get(instance);
if (a == CancelledSubscription.INSTANCE) {
s.cancel();
return false;
}
if (field.compareAndSet(instance, a, s)) {
return true;
}
}
}
/**
* Sets the given subscription once and returns true if successful, false
* if the field has a subscription already or has been cancelled.
* <p>
* If the field already has a subscription, it is cancelled and the duplicate
* subscription is reported (see {@link #reportSubscriptionSet()}).
*
* @param <F> the instance type containing the field
* @param field the field accessor
* @param instance the parent instance
* @param s the subscription to set once
* @return true if successful, false if the target was not empty or has been cancelled
*/
public static <F> boolean setOnce(AtomicReferenceFieldUpdater<F, Subscription> field, F instance, Subscription s) {
Objects.requireNonNull(s, "subscription");
Subscription a = field.get(instance);
if (a == CancelledSubscription.INSTANCE) {
s.cancel();
return false;
}
if (a != null) {
s.cancel();
reportSubscriptionSet();
return false;
}
if (field.compareAndSet(instance, null, s)) {
return true;
}
a = field.get(instance);
if (a == CancelledSubscription.INSTANCE) {
s.cancel();
return false;
}
s.cancel();
reportSubscriptionSet();
return false;
}
/**
* Atomically terminates the subscription if it is not already a
* {@link #cancelledSubscription()}, cancelling the subscription and setting the field
* to the singleton {@link #cancelledSubscription()}.
*
* @param <F> the instance type containing the field
* @param field the field accessor
* @param instance the parent instance
* @return true if terminated, false if the subscription was already terminated
*/
public static <F> boolean terminate(AtomicReferenceFieldUpdater<F, Subscription> field,
F instance) {
Subscription a = field.get(instance);
if (a != CancelledSubscription.INSTANCE) {
a = field.getAndSet(instance, CancelledSubscription.INSTANCE);
if (a != null && a != CancelledSubscription.INSTANCE) {
a.cancel();
return true;
}
}
return false;
}
/**
* Update an empty atomic reference with the given exception, or combine further added
* exceptions together as suppressed exceptions under a root Throwable with
* the {@code "Multiple exceptions"} message, if the atomic reference already holds
* one. This is short-circuited if the reference contains {@link #TERMINATED}.
* <p>
* Since composite exceptions and traceback exceptions share the same underlying mechanism
* of suppressed exceptions, a traceback could be made part of a composite exception.
* Use {@link #unwrapMultipleExcludingTracebacks(Throwable)} to filter out such elements in
* a composite if needed.
*
* @param <T> the parent instance type
* @param field the target field updater
* @param instance the parent instance for the field
* @param exception the Throwable to add.
*
* @return true if added, false if the field contained the {@link #TERMINATED}
* instance.
* @see #unwrapMultiple(Throwable)
*/
public static <T> boolean addThrowable(AtomicReferenceFieldUpdater<T, Throwable> field,
T instance,
Throwable exception) {
for (; ; ) {
Throwable current = field.get(instance);
if (current == TERMINATED) {
return false;
}
if (current instanceof CompositeException) {
//this is ok, composite exceptions are never singletons
current.addSuppressed(exception);
return true;
}
Throwable update;
if (current == null) {
update = exception;
} else {
update = multiple(current, exception);
}
if (field.compareAndSet(instance, current, update)) {
return true;
}
}
}
/**
* Atomic utility to safely mark a volatile throwable reference with a terminal
* marker.
*
* @param field the atomic container
* @param instance the reference instance
* @param <T> the instance type
*
* @return the previously masked throwable
*/
@Nullable
public static <T> Throwable terminate(AtomicReferenceFieldUpdater<T, Throwable> field,
T instance) {
Throwable current = field.get(instance);
if (current != TERMINATED) {
current = field.getAndSet(instance, TERMINATED);
}
return current;
}