diff options
Diffstat (limited to 'guava/src/com/google/common/util/concurrent/AggregateFutureState.java')
-rw-r--r-- | guava/src/com/google/common/util/concurrent/AggregateFutureState.java | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java index 040d81363..f8398d817 100644 --- a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java +++ b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java @@ -37,9 +37,9 @@ import java.util.logging.Logger; */ @GwtCompatible(emulated = true) @ReflectionSupport(value = ReflectionSupport.Level.FULL) -abstract class AggregateFutureState { +abstract class AggregateFutureState<OutputT> extends AbstractFuture.TrustedFuture<OutputT> { // Lazily initialized the first time we see an exception; not released until all the input futures - // & this future completes. Released when the future releases the reference to the running state + // have completed and we have processed them all. private volatile Set<Throwable> seenExceptions = null; private volatile int remaining; @@ -89,12 +89,27 @@ abstract class AggregateFutureState { * Thread2: calls setException(), which returns false, CASes seenExceptions to its exception, * and wrongly believes that its exception is new (leading it to logging it when it shouldn't) * - * Our solution is for threads to CAS seenExceptions from null to a Set population with _the + * Our solution is for threads to CAS seenExceptions from null to a Set populated with _the * initial exception_, no matter which thread does the work. This ensures that seenExceptions * always contains not just the current thread's exception but also the initial thread's. */ Set<Throwable> seenExceptionsLocal = seenExceptions; if (seenExceptionsLocal == null) { + // TODO(cpovirk): Should we use a simpler (presumably cheaper) data structure? + /* + * Using weak references here could let us release exceptions earlier, but: + * + * 1. On Android, querying a WeakReference blocks if the GC is doing an otherwise-concurrent + * pass. + * + * 2. We would probably choose to compare exceptions using == instead of equals() (for + * consistency with how weak references are cleared). That's a behavior change -- arguably the + * removal of a feature. + * + * Fortunately, exceptions rarely contain references to expensive resources. + */ + + // seenExceptionsLocal = newConcurrentHashSet(); /* * Other handleException() callers may see this as soon as we publish it. We need to populate @@ -122,6 +137,10 @@ abstract class AggregateFutureState { return ATOMIC_HELPER.decrementAndGetRemainingCount(this); } + final void clearSeenExceptions() { + seenExceptions = null; + } + private abstract static class AtomicHelper { /** Atomic compare-and-set of the {@link AggregateFutureState#seenExceptions} field. */ abstract void compareAndSetSeenExceptions( @@ -169,8 +188,7 @@ abstract class AggregateFutureState { @Override int decrementAndGetRemainingCount(AggregateFutureState state) { synchronized (state) { - state.remaining--; - return state.remaining; + return --state.remaining; } } } |