Avoid redundant volatile read in DefaultPromise#get() (#9547)
Motivation Currently every call to get() on a promise results in two reads of the volatile result field when one would suffice. Maybe this is optimized away but it seems sensible not to rely on that. Modification Reimplement get() and get(...) in DefaultPromise to reduce volatile access. Result Fewer volatile reads.
This commit is contained in:
parent
acaa29f508
commit
6423e80932
@ -16,7 +16,6 @@
|
|||||||
package io.netty.util.concurrent;
|
package io.netty.util.concurrent;
|
||||||
|
|
||||||
import io.netty.util.internal.InternalThreadLocalMap;
|
import io.netty.util.internal.InternalThreadLocalMap;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.ThrowableUtil;
|
import io.netty.util.internal.ThrowableUtil;
|
||||||
@ -25,7 +24,9 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
|||||||
|
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
@ -145,15 +146,21 @@ public class DefaultPromise<V> implements Promise<V> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Throwable cause() {
|
public Throwable cause() {
|
||||||
Object result = this.result;
|
return cause0(result);
|
||||||
if (result != CANCELLATION_CAUSE_HOLDER) {
|
|
||||||
return (result instanceof CauseHolder) ? ((CauseHolder) result).cause : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Throwable cause0(Object result) {
|
||||||
|
if (!(result instanceof CauseHolder)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (result == CANCELLATION_CAUSE_HOLDER) {
|
||||||
CancellationException ce = new LeanCancellationException();
|
CancellationException ce = new LeanCancellationException();
|
||||||
if (RESULT_UPDATER.compareAndSet(this, CANCELLATION_CAUSE_HOLDER, new CauseHolder(ce))) {
|
if (RESULT_UPDATER.compareAndSet(this, CANCELLATION_CAUSE_HOLDER, new CauseHolder(ce))) {
|
||||||
return ce;
|
return ce;
|
||||||
}
|
}
|
||||||
return ((CauseHolder) this.result).cause;
|
result = this.result;
|
||||||
|
}
|
||||||
|
return ((CauseHolder) result).cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -313,6 +320,50 @@ public class DefaultPromise<V> implements Promise<V> {
|
|||||||
return (V) result;
|
return (V) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public V get() throws InterruptedException, ExecutionException {
|
||||||
|
Object result = this.result;
|
||||||
|
if (!isDone0(result)) {
|
||||||
|
await();
|
||||||
|
result = this.result;
|
||||||
|
}
|
||||||
|
if (result == SUCCESS || result == UNCANCELLABLE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Throwable cause = cause0(result);
|
||||||
|
if (cause == null) {
|
||||||
|
return (V) result;
|
||||||
|
}
|
||||||
|
if (cause instanceof CancellationException) {
|
||||||
|
throw (CancellationException) cause;
|
||||||
|
}
|
||||||
|
throw new ExecutionException(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
Object result = this.result;
|
||||||
|
if (!isDone0(result)) {
|
||||||
|
if (!await(timeout, unit)) {
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
result = this.result;
|
||||||
|
}
|
||||||
|
if (result == SUCCESS || result == UNCANCELLABLE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Throwable cause = cause0(result);
|
||||||
|
if (cause == null) {
|
||||||
|
return (V) result;
|
||||||
|
}
|
||||||
|
if (cause instanceof CancellationException) {
|
||||||
|
throw (CancellationException) cause;
|
||||||
|
}
|
||||||
|
throw new ExecutionException(cause);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user