aboutsummaryrefslogtreecommitdiff
path: root/guava/src/com/google/common/util/concurrent
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/util/concurrent')
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java4
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java14
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractFuture.java56
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractScheduledService.java17
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/AggregateFuture.java7
-rw-r--r--guava/src/com/google/common/util/concurrent/AggregateFutureState.java11
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicLongMap.java10
-rw-r--r--guava/src/com/google/common/util/concurrent/ClosingFuture.java43
-rw-r--r--guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java11
-rw-r--r--guava/src/com/google/common/util/concurrent/ExecutionList.java18
-rw-r--r--guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/Futures.java22
-rw-r--r--guava/src/com/google/common/util/concurrent/FuturesGetChecked.java22
-rw-r--r--guava/src/com/google/common/util/concurrent/ImmediateFuture.java18
-rw-r--r--guava/src/com/google/common/util/concurrent/InterruptibleTask.java2
-rw-r--r--guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java8
-rw-r--r--guava/src/com/google/common/util/concurrent/LazyLogger.java56
-rw-r--r--guava/src/com/google/common/util/concurrent/ListenerCallQueue.java29
-rw-r--r--guava/src/com/google/common/util/concurrent/Monitor.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/MoreExecutors.java12
-rw-r--r--guava/src/com/google/common/util/concurrent/SequentialExecutor.java11
-rw-r--r--guava/src/com/google/common/util/concurrent/ServiceManager.java40
-rw-r--r--guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java13
24 files changed, 280 insertions, 153 deletions
diff --git a/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java b/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java
index e5df53835..8fa650028 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java
@@ -108,8 +108,8 @@ abstract class AbstractCatchingFuture<
+ e.getClass()
+ " without a cause");
}
- } catch (RuntimeException | Error e) { // this includes cancellation exception
- throwable = e;
+ } catch (Throwable t) { // this includes CancellationException and sneaky checked exception
+ throwable = t;
}
if (throwable == null) {
diff --git a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
index c52f9d456..512d80955 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* Base class for services that can implement {@link #startUp}, {@link #run} and {@link #shutDown}
@@ -38,8 +37,7 @@ import java.util.logging.Logger;
@J2ktIncompatible
@ElementTypesAreNonnullByDefault
public abstract class AbstractExecutionThreadService implements Service {
- private static final Logger logger =
- Logger.getLogger(AbstractExecutionThreadService.class.getName());
+ private static final LazyLogger logger = new LazyLogger(AbstractExecutionThreadService.class);
/* use AbstractService for state management */
private final Service delegate =
@@ -66,10 +64,12 @@ public abstract class AbstractExecutionThreadService implements Service {
// TODO(lukes): if guava ever moves to java7, this would be a good
// candidate for a suppressed exception, or maybe we could generalize
// Closer.Suppressor
- logger.log(
- Level.WARNING,
- "Error while attempting to shut down the service after failure.",
- ignored);
+ logger
+ .get()
+ .log(
+ Level.WARNING,
+ "Error while attempting to shut down the service after failure.",
+ ignored);
}
notifyFailed(t);
return;
diff --git a/guava/src/com/google/common/util/concurrent/AbstractFuture.java b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
index 42ec5264c..a886f10c2 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
@@ -42,7 +42,6 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.LockSupport;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -141,8 +140,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
}
}
- // Logger to log exceptions caught when running listeners.
- private static final Logger log = Logger.getLogger(AbstractFuture.class.getName());
+ static final LazyLogger log = new LazyLogger(AbstractFuture.class);
// A heuristic for timed gets. If the remaining timeout is less than this, spin instead of
// blocking. This value is what AbstractQueuedSynchronizer uses.
@@ -157,7 +155,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
try {
helper = new UnsafeAtomicHelper();
- } catch (RuntimeException | Error unsafeFailure) {
+ } catch (Exception | Error unsafeFailure) { // sneaky checked exception
thrownUnsafeFailure = unsafeFailure;
// catch absolutely everything and fall through to our 'SafeAtomicHelper'
// The access control checks that ARFU does means the caller class has to be AbstractFuture
@@ -170,7 +168,8 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
newUpdater(AbstractFuture.class, Waiter.class, "waiters"),
newUpdater(AbstractFuture.class, Listener.class, "listeners"),
newUpdater(AbstractFuture.class, Object.class, "value"));
- } catch (RuntimeException | Error atomicReferenceFieldUpdaterFailure) {
+ } catch (Exception // sneaky checked exception
+ | Error atomicReferenceFieldUpdaterFailure) {
// Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
// getDeclaredField to throw a NoSuchFieldException when the field is definitely there.
// For these users fallback to a suboptimal implementation, based on synchronized. This will
@@ -189,9 +188,12 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
// Log after all static init is finished; if an installed logger uses any Futures methods, it
// shouldn't break in cases where reflection is missing/broken.
if (thrownAtomicReferenceFieldUpdaterFailure != null) {
- log.log(Level.SEVERE, "UnsafeAtomicHelper is broken!", thrownUnsafeFailure);
- log.log(
- Level.SEVERE, "SafeAtomicHelper is broken!", thrownAtomicReferenceFieldUpdaterFailure);
+ log.get().log(Level.SEVERE, "UnsafeAtomicHelper is broken!", thrownUnsafeFailure);
+ log.get()
+ .log(
+ Level.SEVERE,
+ "SafeAtomicHelper is broken!",
+ thrownAtomicReferenceFieldUpdaterFailure);
}
}
@@ -864,14 +866,16 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
// since all we are doing is unpacking a completed future which should be fast.
try {
future.addListener(valueToSet, DirectExecutor.INSTANCE);
- } catch (RuntimeException | Error t) {
+ } catch (Throwable t) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
+ //
// addListener has thrown an exception! SetFuture.run can't throw any exceptions so this
// must have been caused by addListener itself. The most likely explanation is a
// misconfigured mock. Try to switch to Failure.
Failure failure;
try {
failure = new Failure(t);
- } catch (RuntimeException | Error oomMostLikely) {
+ } catch (Exception | Error oomMostLikely) { // sneaky checked exception
failure = Failure.FALLBACK_INSTANCE;
}
// Note: The only way this CAS could fail is if cancel() has raced with us. That is ok.
@@ -966,7 +970,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
cancellation));
}
return new Cancellation(false, cancellation);
- } catch (RuntimeException | Error t) {
+ } catch (Exception | Error t) { // sneaky checked exception
return new Failure(t);
}
}
@@ -1190,6 +1194,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
return null;
}
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addPendingString(StringBuilder builder) {
// Capture current builder length so it can be truncated if this future ends up completing while
// the toString is being calculated
@@ -1206,7 +1211,9 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
String pendingDescription;
try {
pendingDescription = Strings.emptyToNull(pendingToString());
- } catch (RuntimeException | StackOverflowError e) {
+ } catch (Exception | StackOverflowError e) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
+ //
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// subclass is implemented with bugs similar to the subclass.
pendingDescription = "Exception thrown from implementation: " + e.getClass();
@@ -1225,6 +1232,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
}
}
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addDoneString(StringBuilder builder) {
try {
V value = getUninterruptibly(this);
@@ -1235,7 +1243,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
builder.append("FAILURE, cause=[").append(e.getCause()).append("]");
} catch (CancellationException e) {
builder.append("CANCELLED"); // shouldn't be reachable
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
builder.append("UNKNOWN, cause=[").append(e.getClass()).append(" thrown from get()]");
}
}
@@ -1259,6 +1267,7 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
}
/** Helper for printing user supplied objects into our toString method. */
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
// This is some basic recursion detection for when people create cycles via set/setFuture or
// when deep chains of futures exist resulting in a StackOverflowException. We could detect
@@ -1270,7 +1279,9 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
} else {
builder.append(o);
}
- } catch (RuntimeException | StackOverflowError e) {
+ } catch (Exception | StackOverflowError e) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
+ //
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// user object is implemented with bugs similar to the user object.
builder.append("Exception thrown from implementation: ").append(e.getClass());
@@ -1281,17 +1292,22 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
- log.log(
- Level.SEVERE,
- "RuntimeException while executing runnable " + runnable + " with executor " + executor,
- e);
+ log.get()
+ .log(
+ Level.SEVERE,
+ "RuntimeException while executing runnable "
+ + runnable
+ + " with executor "
+ + executor,
+ e);
}
}
@@ -1371,8 +1387,6 @@ public abstract class AbstractFuture<V extends @Nullable Object> extends Interna
UNSAFE = unsafe;
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
- } catch (RuntimeException e) {
- throw e;
}
}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
index 164a6dbb4..2529d4749 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
@@ -40,7 +40,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -105,7 +104,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
@J2ktIncompatible
@ElementTypesAreNonnullByDefault
public abstract class AbstractScheduledService implements Service {
- private static final Logger logger = Logger.getLogger(AbstractScheduledService.class.getName());
+ private static final LazyLogger logger = new LazyLogger(AbstractScheduledService.class);
/**
* A scheduler defines the policy for how the {@link AbstractScheduledService} should run its
@@ -239,10 +238,12 @@ public abstract class AbstractScheduledService implements Service {
shutDown();
} catch (Exception ignored) {
restoreInterruptIfIsInterruptedException(ignored);
- logger.log(
- Level.WARNING,
- "Error while attempting to shut down the service after failure.",
- ignored);
+ logger
+ .get()
+ .log(
+ Level.WARNING,
+ "Error while attempting to shut down the service after failure.",
+ ignored);
}
notifyFailed(t);
// requireNonNull is safe now, just as it was above.
@@ -606,7 +607,9 @@ public abstract class AbstractScheduledService implements Service {
lock.lock();
try {
toReturn = initializeOrUpdateCancellationDelegate(schedule);
- } catch (RuntimeException | Error e) {
+ } catch (Throwable e) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
+ //
// If an exception is thrown by the subclass then we need to make sure that the service
// notices and transitions to the FAILED state. We do it by calling notifyFailed directly
// because the service does not monitor the state of the future so if the exception is not
diff --git a/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java b/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java
index 5581b5fae..3c5f30b63 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java
@@ -66,6 +66,7 @@ abstract class AbstractTransformFuture<
}
@Override
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public final void run() {
ListenableFuture<? extends I> localInputFuture = inputFuture;
F localFunction = function;
@@ -104,7 +105,7 @@ abstract class AbstractTransformFuture<
// Set the cause of the exception as this future's exception.
setException(e.getCause());
return;
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// Bug in inputFuture.get(). Propagate to the output Future so that its consumers don't hang.
setException(e);
return;
diff --git a/guava/src/com/google/common/util/concurrent/AggregateFuture.java b/guava/src/com/google/common/util/concurrent/AggregateFuture.java
index ec96cbb89..353477416 100644
--- a/guava/src/com/google/common/util/concurrent/AggregateFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AggregateFuture.java
@@ -30,7 +30,6 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -44,7 +43,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
@ElementTypesAreNonnullByDefault
abstract class AggregateFuture<InputT extends @Nullable Object, OutputT extends @Nullable Object>
extends AggregateFutureState<OutputT> {
- private static final Logger logger = Logger.getLogger(AggregateFuture.class.getName());
+ private static final LazyLogger logger = new LazyLogger(AggregateFuture.class);
/**
* The input futures. After {@link #init}, this field is read only by {@link #afterDone()} (to
@@ -230,7 +229,7 @@ abstract class AggregateFuture<InputT extends @Nullable Object, OutputT extends
(throwable instanceof Error)
? "Input Future failed with Error"
: "Got more than one input Future failure. Logging failures after the first";
- logger.log(SEVERE, message, throwable);
+ logger.get().log(SEVERE, message, throwable);
}
@Override
@@ -268,7 +267,7 @@ abstract class AggregateFuture<InputT extends @Nullable Object, OutputT extends
collectOneValue(index, getDone(future));
} catch (ExecutionException e) {
handleException(e.getCause());
- } catch (RuntimeException | Error t) {
+ } catch (Throwable t) { // sneaky checked exception
handleException(t);
}
}
diff --git a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java
index 7bdec0135..5816abf05 100644
--- a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java
+++ b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java
@@ -25,7 +25,6 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -51,7 +50,7 @@ abstract class AggregateFutureState<OutputT extends @Nullable Object>
private static final AtomicHelper ATOMIC_HELPER;
- private static final Logger log = Logger.getLogger(AggregateFutureState.class.getName());
+ private static final LazyLogger log = new LazyLogger(AggregateFutureState.class);
static {
AtomicHelper helper;
@@ -61,7 +60,7 @@ abstract class AggregateFutureState<OutputT extends @Nullable Object>
new SafeAtomicHelper(
newUpdater(AggregateFutureState.class, Set.class, "seenExceptions"),
newUpdater(AggregateFutureState.class, "remaining"));
- } catch (RuntimeException | Error reflectionFailure) {
+ } catch (Throwable reflectionFailure) { // sneaky checked exception
// Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
// getDeclaredField to throw a NoSuchFieldException when the field is definitely there.
// For these users fallback to a suboptimal implementation, based on synchronized. This will
@@ -73,7 +72,7 @@ abstract class AggregateFutureState<OutputT extends @Nullable Object>
// Log after all static init is finished; if an installed logger uses any Futures methods, it
// shouldn't break in cases where reflection is missing/broken.
if (thrownReflectionFailure != null) {
- log.log(Level.SEVERE, "SafeAtomicHelper is broken!", thrownReflectionFailure);
+ log.get().log(Level.SEVERE, "SafeAtomicHelper is broken!", thrownReflectionFailure);
}
}
@@ -159,7 +158,7 @@ abstract class AggregateFutureState<OutputT extends @Nullable Object>
}
private static final class SafeAtomicHelper extends AtomicHelper {
- final AtomicReferenceFieldUpdater<AggregateFutureState<?>, Set<Throwable>>
+ final AtomicReferenceFieldUpdater<AggregateFutureState<?>, @Nullable Set<Throwable>>
seenExceptionsUpdater;
final AtomicIntegerFieldUpdater<AggregateFutureState<?>> remainingCountUpdater;
@@ -169,7 +168,7 @@ abstract class AggregateFutureState<OutputT extends @Nullable Object>
AtomicReferenceFieldUpdater seenExceptionsUpdater,
AtomicIntegerFieldUpdater remainingCountUpdater) {
this.seenExceptionsUpdater =
- (AtomicReferenceFieldUpdater<AggregateFutureState<?>, Set<Throwable>>)
+ (AtomicReferenceFieldUpdater<AggregateFutureState<?>, @Nullable Set<Throwable>>)
seenExceptionsUpdater;
this.remainingCountUpdater =
(AtomicIntegerFieldUpdater<AggregateFutureState<?>>) remainingCountUpdater;
diff --git a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
index 28481cca5..4ede5d606 100644
--- a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
+++ b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
@@ -17,6 +17,7 @@
package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.J2ktIncompatible;
@@ -147,8 +148,11 @@ public final class AtomicLongMap<K> implements Serializable {
@CanIgnoreReturnValue
public long updateAndGet(K key, LongUnaryOperator updaterFunction) {
checkNotNull(updaterFunction);
- return map.compute(
- key, (k, value) -> updaterFunction.applyAsLong((value == null) ? 0L : value.longValue()));
+ Long result =
+ map.compute(
+ key,
+ (k, value) -> updaterFunction.applyAsLong((value == null) ? 0L : value.longValue()));
+ return requireNonNull(result);
}
/**
@@ -329,7 +333,7 @@ public final class AtomicLongMap<K> implements Serializable {
return oldValue;
}
});
- return noValue.get() ? 0L : result.longValue();
+ return noValue.get() ? 0L : requireNonNull(result).longValue();
}
/**
diff --git a/guava/src/com/google/common/util/concurrent/ClosingFuture.java b/guava/src/com/google/common/util/concurrent/ClosingFuture.java
index 79aa0aa0e..efdf56d8a 100644
--- a/guava/src/com/google/common/util/concurrent/ClosingFuture.java
+++ b/guava/src/com/google/common/util/concurrent/ClosingFuture.java
@@ -58,7 +58,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -196,7 +195,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
// TODO(dpb): GWT compatibility.
public final class ClosingFuture<V extends @Nullable Object> {
- private static final Logger logger = Logger.getLogger(ClosingFuture.class.getName());
+ private static final LazyLogger logger = new LazyLogger(ClosingFuture.class);
/**
* An object that can capture objects to be closed later, when a {@link ClosingFuture} pipeline is
@@ -681,7 +680,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
*
* <p>After calling this method, you may not call {@link #finishToFuture()}, {@link
* #finishToValueAndCloser(ValueAndCloserConsumer, Executor)}, or any other derivation method on
- * this {@code ClosingFuture}.
+ * the original {@code ClosingFuture} instance.
*
* @param function transforms the value of this step to the value of the derived step
* @param executor executor to run the function in
@@ -774,7 +773,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
*
* <p>After calling this method, you may not call {@link #finishToFuture()}, {@link
* #finishToValueAndCloser(ValueAndCloserConsumer, Executor)}, or any other derivation method on
- * this {@code ClosingFuture}.
+ * the original {@code ClosingFuture} instance.
*
* @param function transforms the value of this step to a {@code ClosingFuture} with the value of
* the derived step
@@ -865,7 +864,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
*
* <p>After calling this method, you may not call {@link #finishToFuture()}, {@link
* #finishToValueAndCloser(ValueAndCloserConsumer, Executor)}, or any other derivation method on
- * this {@code ClosingFuture}.
+ * the original {@code ClosingFuture} instance.
*
* @param exceptionType the exception type that triggers use of {@code fallback}. The exception
* type is matched against this step's exception. "This step's exception" means the cause of
@@ -958,7 +957,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
*
* <p>After calling this method, you may not call {@link #finishToFuture()}, {@link
* #finishToValueAndCloser(ValueAndCloserConsumer, Executor)}, or any other derivation method on
- * this {@code ClosingFuture}.
+ * the original {@code ClosingFuture} instance.
*
* @param exceptionType the exception type that triggers use of {@code fallback}. The exception
* type is matched against this step's exception. "This step's exception" means the cause of
@@ -1015,13 +1014,13 @@ public final class ClosingFuture<V extends @Nullable Object> {
*
* <p>After calling this method, you may not call {@link
* #finishToValueAndCloser(ValueAndCloserConsumer, Executor)}, this method, or any other
- * derivation method on this {@code ClosingFuture}.
+ * derivation method on the original {@code ClosingFuture} instance.
*
* @return a {@link Future} that represents the final value or exception of the pipeline
*/
public FluentFuture<V> finishToFuture() {
if (compareAndUpdateState(OPEN, WILL_CLOSE)) {
- logger.log(FINER, "will close {0}", this);
+ logger.get().log(FINER, "will close {0}", this);
future.addListener(
new Runnable() {
@Override
@@ -1060,7 +1059,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
* receiver can store the {@link ValueAndCloser} outside the receiver for later synchronous use.
*
* <p>After calling this method, you may not call {@link #finishToFuture()}, this method again, or
- * any other derivation method on this {@code ClosingFuture}.
+ * any other derivation method on the original {@code ClosingFuture} instance.
*
* @param consumer a callback whose method will be called (using {@code executor}) when this
* operation is done
@@ -1121,7 +1120,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
*/
@CanIgnoreReturnValue
public boolean cancel(boolean mayInterruptIfRunning) {
- logger.log(FINER, "cancelling {0}", this);
+ logger.get().log(FINER, "cancelling {0}", this);
boolean cancelled = future.cancel(mayInterruptIfRunning);
if (cancelled) {
close();
@@ -1130,7 +1129,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
}
private void close() {
- logger.log(FINER, "closing {0}", this);
+ logger.get().log(FINER, "closing {0}", this);
closeables.close();
}
@@ -2144,7 +2143,7 @@ public final class ClosingFuture<V extends @Nullable Object> {
@Override
protected void finalize() {
if (state.get().equals(OPEN)) {
- logger.log(SEVERE, "Uh oh! An open ClosingFuture has leaked and will close: {0}", this);
+ logger.get().log(SEVERE, "Uh oh! An open ClosingFuture has leaked and will close: {0}", this);
FluentFuture<V> unused = finishToFuture();
}
}
@@ -2159,14 +2158,26 @@ public final class ClosingFuture<V extends @Nullable Object> {
try {
closeable.close();
} catch (Exception e) {
+ /*
+ * In guava-jre, any kind of Exception may be thrown because `closeable` has type
+ * `AutoCloseable`.
+ *
+ * In guava-android, the only kinds of Exception that may be thrown are
+ * RuntimeException and IOException because `closeable` has type `Closeable`—except
+ * that we have to account for sneaky checked exception.
+ */
restoreInterruptIfIsInterruptedException(e);
- logger.log(WARNING, "thrown by close()", e);
+ logger.get().log(WARNING, "thrown by close()", e);
}
});
} catch (RejectedExecutionException e) {
- if (logger.isLoggable(WARNING)) {
- logger.log(
- WARNING, String.format("while submitting close to %s; will close inline", executor), e);
+ if (logger.get().isLoggable(WARNING)) {
+ logger
+ .get()
+ .log(
+ WARNING,
+ String.format("while submitting close to %s; will close inline", executor),
+ e);
}
closeQuietly(closeable, directExecutor());
}
diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
index 0ec799cc4..6e2ae47a3 100644
--- a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
+++ b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
@@ -41,7 +41,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
/**
@@ -211,7 +210,7 @@ public class CycleDetectingLockFactory {
WARN {
@Override
public void handlePotentialDeadlock(PotentialDeadlockException e) {
- logger.log(Level.SEVERE, "Detected potential deadlock", e);
+ logger.get().log(Level.SEVERE, "Detected potential deadlock", e);
}
},
@@ -447,7 +446,7 @@ public class CycleDetectingLockFactory {
//////// Implementation /////////
- private static final Logger logger = Logger.getLogger(CycleDetectingLockFactory.class.getName());
+ private static final LazyLogger logger = new LazyLogger(CycleDetectingLockFactory.class);
final Policy policy;
@@ -711,7 +710,8 @@ public class CycleDetectingLockFactory {
*/
private void aboutToAcquire(CycleDetectingLock lock) {
if (!lock.isAcquiredByCurrentThread()) {
- ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
+ // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get
+ ArrayList<LockGraphNode> acquiredLockList = requireNonNull(acquiredLocks.get());
LockGraphNode node = lock.getLockGraphNode();
node.checkAcquiredLocks(policy, acquiredLockList);
acquiredLockList.add(node);
@@ -725,7 +725,8 @@ public class CycleDetectingLockFactory {
*/
private static void lockStateChanged(CycleDetectingLock lock) {
if (!lock.isAcquiredByCurrentThread()) {
- ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
+ // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get
+ ArrayList<LockGraphNode> acquiredLockList = requireNonNull(acquiredLocks.get());
LockGraphNode node = lock.getLockGraphNode();
// Iterate in reverse because locks are usually locked/unlocked in a
// LIFO order.
diff --git a/guava/src/com/google/common/util/concurrent/ExecutionList.java b/guava/src/com/google/common/util/concurrent/ExecutionList.java
index 645817c4a..10b933aa1 100644
--- a/guava/src/com/google/common/util/concurrent/ExecutionList.java
+++ b/guava/src/com/google/common/util/concurrent/ExecutionList.java
@@ -21,7 +21,6 @@ import com.google.common.annotations.J2ktIncompatible;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import java.util.concurrent.Executor;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
/**
@@ -45,7 +44,7 @@ import javax.annotation.CheckForNull;
@ElementTypesAreNonnullByDefault
public final class ExecutionList {
/** Logger to log exceptions caught when running runnables. */
- private static final Logger log = Logger.getLogger(ExecutionList.class.getName());
+ private static final LazyLogger log = new LazyLogger(ExecutionList.class);
/**
* The runnable, executor pairs to execute. This acts as a stack threaded through the {@link
@@ -140,17 +139,22 @@ public final class ExecutionList {
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
- log.log(
- Level.SEVERE,
- "RuntimeException while executing runnable " + runnable + " with executor " + executor,
- e);
+ log.get()
+ .log(
+ Level.SEVERE,
+ "RuntimeException while executing runnable "
+ + runnable
+ + " with executor "
+ + executor,
+ e);
}
}
diff --git a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
index 1c16cfb14..0f8a17894 100644
--- a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
+++ b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
@@ -77,12 +77,13 @@ public final class FakeTimeLimiter implements TimeLimiter {
}
@Override
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public void runWithTimeout(Runnable runnable, long timeoutDuration, TimeUnit timeoutUnit) {
checkNotNull(runnable);
checkNotNull(timeoutUnit);
try {
runnable.run();
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
throw new UncheckedExecutionException(e);
} catch (Error e) {
throw new ExecutionError(e);
diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java
index 31889609a..6e8d20193 100644
--- a/guava/src/com/google/common/util/concurrent/Futures.java
+++ b/guava/src/com/google/common/util/concurrent/Futures.java
@@ -545,7 +545,8 @@ public final class Futures extends GwtFuturesCatchingSpecialization {
private O applyTransformation(I input) throws ExecutionException {
try {
return function.apply(input);
- } catch (RuntimeException | Error t) {
+ } catch (Throwable t) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
throw new ExecutionException(t);
}
}
@@ -1126,7 +1127,8 @@ public final class Futures extends GwtFuturesCatchingSpecialization {
} catch (ExecutionException e) {
callback.onFailure(e.getCause());
return;
- } catch (RuntimeException | Error e) {
+ } catch (Throwable e) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
callback.onFailure(e);
return;
}
@@ -1202,10 +1204,10 @@ public final class Futures extends GwtFuturesCatchingSpecialization {
*
* <p>Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor
* that accepts zero or more arguments, all of type {@code String} or {@code Throwable}
- * (preferring constructors with at least one {@code String}) and calling the constructor via
- * reflection. If the exception did not already have a cause, one is set by calling {@link
- * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code
- * IllegalArgumentException} is thrown.
+ * (preferring constructors with at least one {@code String}, then preferring constructors with at
+ * least one {@code Throwable}) and calling the constructor via reflection. If the exception did
+ * not already have a cause, one is set by calling {@link Throwable#initCause(Throwable)} on it.
+ * If no such constructor exists, an {@code IllegalArgumentException} is thrown.
*
* @throws X if {@code get} throws any checked exception except for an {@code ExecutionException}
* whose cause is not itself a checked exception
@@ -1254,10 +1256,10 @@ public final class Futures extends GwtFuturesCatchingSpecialization {
*
* <p>Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor
* that accepts zero or more arguments, all of type {@code String} or {@code Throwable}
- * (preferring constructors with at least one {@code String}) and calling the constructor via
- * reflection. If the exception did not already have a cause, one is set by calling {@link
- * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code
- * IllegalArgumentException} is thrown.
+ * (preferring constructors with at least one {@code String}, then preferring constructors with at
+ * least one {@code Throwable}) and calling the constructor via reflection. If the exception did
+ * not already have a cause, one is set by calling {@link Throwable#initCause(Throwable)} on it.
+ * If no such constructor exists, an {@code IllegalArgumentException} is thrown.
*
* @throws X if {@code get} throws any checked exception except for an {@code ExecutionException}
* whose cause is not itself a checked exception
diff --git a/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java b/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java
index c512d82ee..17e0675b6 100644
--- a/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java
+++ b/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java
@@ -21,7 +21,6 @@ import static java.util.Arrays.asList;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.J2ktIncompatible;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.J2ObjCIncompatible;
@@ -225,7 +224,7 @@ final class FuturesGetChecked {
try {
Exception unused = newWithCause(exceptionClass, new Exception());
return true;
- } catch (RuntimeException | Error e) {
+ } catch (Throwable t) { // sneaky checked exception
return false;
}
}
@@ -234,7 +233,7 @@ final class FuturesGetChecked {
// getConstructors() guarantees this as long as we don't modify the array.
@SuppressWarnings({"unchecked", "rawtypes"})
List<Constructor<X>> constructors = (List) Arrays.asList(exceptionClass.getConstructors());
- for (Constructor<X> constructor : preferringStrings(constructors)) {
+ for (Constructor<X> constructor : preferringStringsThenThrowables(constructors)) {
X instance = newFromConstructor(constructor, cause);
if (instance != null) {
if (instance.getCause() == null) {
@@ -250,17 +249,22 @@ final class FuturesGetChecked {
cause);
}
- private static <X extends Exception> List<Constructor<X>> preferringStrings(
+ private static <X extends Exception> List<Constructor<X>> preferringStringsThenThrowables(
List<Constructor<X>> constructors) {
- return WITH_STRING_PARAM_FIRST.sortedCopy(constructors);
+ return WITH_STRING_PARAM_THEN_WITH_THROWABLE_PARAM.sortedCopy(constructors);
}
- private static final Ordering<Constructor<?>> WITH_STRING_PARAM_FIRST =
+ // TODO: b/296487962 - Consider defining a total order over constructors.
+ private static final Ordering<List<Class<?>>> ORDERING_BY_CONSTRUCTOR_PARAMETER_LIST =
Ordering.natural()
- .onResultOf(
- (Function<Constructor<?>, Boolean>)
- input -> asList(input.getParameterTypes()).contains(String.class))
+ .onResultOf((List<Class<?>> params) -> params.contains(String.class))
+ .compound(
+ Ordering.natural()
+ .onResultOf((List<Class<?>> params) -> params.contains(Throwable.class)))
.reverse();
+ private static final Ordering<Constructor<?>> WITH_STRING_PARAM_THEN_WITH_THROWABLE_PARAM =
+ ORDERING_BY_CONSTRUCTOR_PARAMETER_LIST.onResultOf(
+ constructor -> asList(constructor.getParameterTypes()));
@CheckForNull
private static <X> X newFromConstructor(Constructor<X> constructor, Throwable cause) {
diff --git a/guava/src/com/google/common/util/concurrent/ImmediateFuture.java b/guava/src/com/google/common/util/concurrent/ImmediateFuture.java
index f09816c4e..62ae63eaa 100644
--- a/guava/src/com/google/common/util/concurrent/ImmediateFuture.java
+++ b/guava/src/com/google/common/util/concurrent/ImmediateFuture.java
@@ -22,7 +22,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -33,7 +32,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
class ImmediateFuture<V extends @Nullable Object> implements ListenableFuture<V> {
static final ListenableFuture<?> NULL = new ImmediateFuture<@Nullable Object>(null);
- private static final Logger log = Logger.getLogger(ImmediateFuture.class.getName());
+ private static final LazyLogger log = new LazyLogger(ImmediateFuture.class);
@ParametricNullness private final V value;
@@ -42,18 +41,23 @@ class ImmediateFuture<V extends @Nullable Object> implements ListenableFuture<V>
}
@Override
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public void addListener(Runnable listener, Executor executor) {
checkNotNull(listener, "Runnable was null.");
checkNotNull(executor, "Executor was null.");
try {
executor.execute(listener);
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// ListenableFuture's contract is that it will not throw unchecked exceptions, so log the bad
// runnable and/or executor and swallow it.
- log.log(
- Level.SEVERE,
- "RuntimeException while executing runnable " + listener + " with executor " + executor,
- e);
+ log.get()
+ .log(
+ Level.SEVERE,
+ "RuntimeException while executing runnable "
+ + listener
+ + " with executor "
+ + executor,
+ e);
}
}
diff --git a/guava/src/com/google/common/util/concurrent/InterruptibleTask.java b/guava/src/com/google/common/util/concurrent/InterruptibleTask.java
index 6f33c5032..effa8ef59 100644
--- a/guava/src/com/google/common/util/concurrent/InterruptibleTask.java
+++ b/guava/src/com/google/common/util/concurrent/InterruptibleTask.java
@@ -23,6 +23,7 @@ import com.google.j2objc.annotations.ReflectionSupport;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.AbstractOwnableSynchronizer;
import java.util.concurrent.locks.LockSupport;
+import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@GwtCompatible(emulated = true)
@@ -234,6 +235,7 @@ abstract class InterruptibleTask<T extends @Nullable Object>
}
@VisibleForTesting
+ @CheckForNull
Thread getOwner() {
return super.getExclusiveOwnerThread();
}
diff --git a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
index 33403c978..eb3a24707 100644
--- a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
+++ b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
@@ -19,7 +19,6 @@ import static com.google.common.util.concurrent.Uninterruptibles.getUninterrupti
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.J2ktIncompatible;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -162,10 +161,11 @@ public final class JdkFutureAdapters {
* to return a proper ListenableFuture instead of using listenInPoolThread.
*/
getUninterruptibly(delegate);
- } catch (ExecutionException | RuntimeException | Error e) {
- // (including CancellationException)
+ } catch (Throwable t) {
+ // (including CancellationException and sneaky checked exception)
// The task is presumably done, run the listeners.
- // TODO(cpovirk): Do *something* in case of Error (and maybe RuntimeException)?
+ // TODO(cpovirk): Do *something* in case of Error (and maybe
+ // non-CancellationException, non-ExecutionException exceptions)?
}
executionList.execute();
});
diff --git a/guava/src/com/google/common/util/concurrent/LazyLogger.java b/guava/src/com/google/common/util/concurrent/LazyLogger.java
new file mode 100644
index 000000000..9ae0f784e
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/LazyLogger.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import com.google.common.annotations.GwtCompatible;
+import java.util.logging.Logger;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/** A holder for a {@link Logger} that is initialized only when requested. */
+@GwtCompatible
+@ElementTypesAreNonnullByDefault
+final class LazyLogger {
+ private final String loggerName;
+ private volatile @Nullable Logger logger;
+
+ LazyLogger(Class<?> ownerOfLogger) {
+ this.loggerName = ownerOfLogger.getName();
+ }
+
+ Logger get() {
+ /*
+ * We use double-checked locking. We could the try racy single-check idiom, but that would
+ * depend on Logger not contain mutable state.
+ *
+ * We could use Suppliers.memoizingSupplier here, but I micro-optimized to this implementation
+ * to avoid the extra class for the lambda (and maybe more for memoizingSupplier itself) and the
+ * indirection.
+ *
+ * One thing to *avoid* is a change to make each Logger user use memoizingSupplier directly:
+ * That may introduce an extra class for each lambda (currently a dozen).
+ */
+ Logger local = logger;
+ if (local != null) {
+ return local;
+ }
+ synchronized (this) {
+ local = logger;
+ if (local != null) {
+ return local;
+ }
+ return logger = Logger.getLogger(loggerName);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
index 4ef7ed36c..e6284e1c7 100644
--- a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
+++ b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
@@ -27,7 +27,6 @@ import java.util.List;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* A list of listeners for implementing a concurrency friendly observable object.
@@ -58,7 +57,7 @@ import java.util.logging.Logger;
@ElementTypesAreNonnullByDefault
final class ListenerCallQueue<L> {
// TODO(cpovirk): consider using the logger associated with listener.getClass().
- private static final Logger logger = Logger.getLogger(ListenerCallQueue.class.getName());
+ private static final LazyLogger logger = new LazyLogger(ListenerCallQueue.class);
// TODO(chrisn): promote AppendOnlyCollection for use here.
private final List<PerListenerQueue<L>> listeners =
@@ -159,6 +158,7 @@ final class ListenerCallQueue<L> {
* Dispatches all listeners {@linkplain #enqueue enqueued} prior to this call, serially and in
* order.
*/
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
void dispatch() {
boolean scheduleEventRunner = false;
synchronized (this) {
@@ -170,22 +170,25 @@ final class ListenerCallQueue<L> {
if (scheduleEventRunner) {
try {
executor.execute(this);
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// reset state in case of an error so that later dispatch calls will actually do something
synchronized (this) {
isThreadScheduled = false;
}
// Log it and keep going.
- logger.log(
- Level.SEVERE,
- "Exception while running callbacks for " + listener + " on " + executor,
- e);
+ logger
+ .get()
+ .log(
+ Level.SEVERE,
+ "Exception while running callbacks for " + listener + " on " + executor,
+ e);
throw e;
}
}
}
@Override
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public void run() {
boolean stillRunning = true;
try {
@@ -206,12 +209,14 @@ final class ListenerCallQueue<L> {
// Always run while _not_ holding the lock, to avoid deadlocks.
try {
nextToRun.call(listener);
- } catch (RuntimeException e) {
+ } catch (Exception e) { // sneaky checked exception
// Log it and keep going.
- logger.log(
- Level.SEVERE,
- "Exception while executing callback: " + listener + " " + nextLabel,
- e);
+ logger
+ .get()
+ .log(
+ Level.SEVERE,
+ "Exception while executing callback: " + listener + " " + nextLabel,
+ e);
}
}
} finally {
diff --git a/guava/src/com/google/common/util/concurrent/Monitor.java b/guava/src/com/google/common/util/concurrent/Monitor.java
index 2ed31eda4..1abbc6405 100644
--- a/guava/src/com/google/common/util/concurrent/Monitor.java
+++ b/guava/src/com/google/common/util/concurrent/Monitor.java
@@ -1123,7 +1123,8 @@ public final class Monitor {
private boolean isSatisfied(Guard guard) {
try {
return guard.isSatisfied();
- } catch (RuntimeException | Error throwable) {
+ } catch (Throwable throwable) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
signalAllWaiters();
throw throwable;
}
diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
index ea3536957..46536fbe7 100644
--- a/guava/src/com/google/common/util/concurrent/MoreExecutors.java
+++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
@@ -739,7 +739,8 @@ public final class MoreExecutors {
public void run() {
try {
delegate.run();
- } catch (RuntimeException | Error t) {
+ } catch (Throwable t) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
setException(t);
throw t;
}
@@ -784,7 +785,10 @@ public final class MoreExecutors {
* An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService}
* implementations.
*/
- @SuppressWarnings("GoodTime") // should accept a java.time.Duration
+ @SuppressWarnings({
+ "GoodTime", // should accept a java.time.Duration
+ "CatchingUnchecked", // sneaky checked exception
+ })
@J2ktIncompatible
@GwtIncompatible
@ParametricNullness
@@ -847,7 +851,9 @@ public final class MoreExecutors {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
- } catch (RuntimeException rex) {
+ } catch (InterruptedException iex) {
+ throw iex;
+ } catch (Exception rex) { // sneaky checked exception
ee = new ExecutionException(rex);
}
}
diff --git a/guava/src/com/google/common/util/concurrent/SequentialExecutor.java b/guava/src/com/google/common/util/concurrent/SequentialExecutor.java
index c842d7e07..ebc33178d 100644
--- a/guava/src/com/google/common/util/concurrent/SequentialExecutor.java
+++ b/guava/src/com/google/common/util/concurrent/SequentialExecutor.java
@@ -31,7 +31,6 @@ import java.util.Deque;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.CheckForNull;
/**
@@ -52,7 +51,7 @@ import javax.annotation.CheckForNull;
@GwtIncompatible
@ElementTypesAreNonnullByDefault
final class SequentialExecutor implements Executor {
- private static final Logger log = Logger.getLogger(SequentialExecutor.class.getName());
+ private static final LazyLogger log = new LazyLogger(SequentialExecutor.class);
enum WorkerRunningState {
/** Runnable is not running and not queued for execution */
@@ -136,7 +135,8 @@ final class SequentialExecutor implements Executor {
try {
executor.execute(worker);
- } catch (RuntimeException | Error t) {
+ } catch (Throwable t) {
+ // Any Exception is either a RuntimeException or sneaky checked exception.
synchronized (queue) {
boolean removed =
(workerRunningState == IDLE || workerRunningState == QUEUING)
@@ -202,6 +202,7 @@ final class SequentialExecutor implements Executor {
* will still be present. If the composed Executor is an ExecutorService, it can respond to
* shutdown() by returning tasks queued on that Thread after {@link #worker} drains the queue.
*/
+ @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void workOnQueue() {
boolean interruptedDuringTask = false;
boolean hasSetRunning = false;
@@ -235,8 +236,8 @@ final class SequentialExecutor implements Executor {
interruptedDuringTask |= Thread.interrupted();
try {
task.run();
- } catch (RuntimeException e) {
- log.log(Level.SEVERE, "Exception while executing runnable " + task, e);
+ } catch (Exception e) { // sneaky checked exception
+ log.get().log(Level.SEVERE, "Exception while executing runnable " + task, e);
} finally {
task = null;
}
diff --git a/guava/src/com/google/common/util/concurrent/ServiceManager.java b/guava/src/com/google/common/util/concurrent/ServiceManager.java
index 42652c967..0bda0afec 100644
--- a/guava/src/com/google/common/util/concurrent/ServiceManager.java
+++ b/guava/src/com/google/common/util/concurrent/ServiceManager.java
@@ -65,7 +65,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* A manager for monitoring and controlling a set of {@linkplain Service services}. This class
@@ -125,7 +124,7 @@ import java.util.logging.Logger;
@GwtIncompatible
@ElementTypesAreNonnullByDefault
public final class ServiceManager implements ServiceManagerBridge {
- private static final Logger logger = Logger.getLogger(ServiceManager.class.getName());
+ private static final LazyLogger logger = new LazyLogger(ServiceManager.class);
private static final ListenerCallQueue.Event<Listener> HEALTHY_EVENT =
new ListenerCallQueue.Event<Listener>() {
@Override
@@ -208,10 +207,13 @@ public final class ServiceManager implements ServiceManagerBridge {
if (copy.isEmpty()) {
// Having no services causes the manager to behave strangely. Notably, listeners are never
// fired. To avoid this we substitute a placeholder service.
- logger.log(
- Level.WARNING,
- "ServiceManager configured with no services. Is your application configured properly?",
- new EmptyServiceManagerWarning());
+ logger
+ .get()
+ .log(
+ Level.WARNING,
+ "ServiceManager configured with no services. Is your application configured"
+ + " properly?",
+ new EmptyServiceManagerWarning());
copy = ImmutableList.<Service>of(new NoOpService());
}
this.state = new ServiceManagerState(copy);
@@ -278,7 +280,7 @@ public final class ServiceManager implements ServiceManagerBridge {
// service or listener). Our contract says it is safe to call this method if
// all services were NEW when it was called, and this has already been verified above, so we
// don't propagate the exception.
- logger.log(Level.WARNING, "Unable to start Service " + service, e);
+ logger.get().log(Level.WARNING, "Unable to start Service " + service, e);
}
}
return this;
@@ -706,7 +708,7 @@ public final class ServiceManager implements ServiceManagerBridge {
// N.B. if we miss the STARTING event then we may never record a startup time.
stopwatch.stop();
if (!(service instanceof NoOpService)) {
- logger.log(Level.FINE, "Started {0} in {1}.", new Object[] {service, stopwatch});
+ logger.get().log(Level.FINE, "Started {0} in {1}.", new Object[] {service, stopwatch});
}
}
// Queue our listeners
@@ -798,7 +800,7 @@ public final class ServiceManager implements ServiceManagerBridge {
if (state != null) {
state.transitionService(service, NEW, STARTING);
if (!(service instanceof NoOpService)) {
- logger.log(Level.FINE, "Starting {0}.", service);
+ logger.get().log(Level.FINE, "Starting {0}.", service);
}
}
}
@@ -824,10 +826,12 @@ public final class ServiceManager implements ServiceManagerBridge {
ServiceManagerState state = this.state.get();
if (state != null) {
if (!(service instanceof NoOpService)) {
- logger.log(
- Level.FINE,
- "Service {0} has terminated. Previous state was: {1}",
- new Object[] {service, from});
+ logger
+ .get()
+ .log(
+ Level.FINE,
+ "Service {0} has terminated. Previous state was: {1}",
+ new Object[] {service, from});
}
state.transitionService(service, from, TERMINATED);
}
@@ -846,10 +850,12 @@ public final class ServiceManager implements ServiceManagerBridge {
*/
log &= from != State.STARTING;
if (log) {
- logger.log(
- Level.SEVERE,
- "Service " + service + " has failed in the " + from + " state.",
- failure);
+ logger
+ .get()
+ .log(
+ Level.SEVERE,
+ "Service " + service + " has failed in the " + from + " state.",
+ failure);
}
state.transitionService(service, from, FAILED);
}
diff --git a/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java b/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java
index 1dc1094d4..9890c89d6 100644
--- a/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java
+++ b/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java
@@ -21,7 +21,6 @@ import com.google.common.annotations.J2ktIncompatible;
import com.google.common.annotations.VisibleForTesting;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Locale;
-import java.util.logging.Logger;
/**
* Factories for {@link UncaughtExceptionHandler} instances.
@@ -57,7 +56,7 @@ public final class UncaughtExceptionHandlers {
@VisibleForTesting
static final class Exiter implements UncaughtExceptionHandler {
- private static final Logger logger = Logger.getLogger(Exiter.class.getName());
+ private static final LazyLogger logger = new LazyLogger(Exiter.class);
private final Runtime runtime;
@@ -68,9 +67,13 @@ public final class UncaughtExceptionHandlers {
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
- logger.log(
- SEVERE, String.format(Locale.ROOT, "Caught an exception in %s. Shutting down.", t), e);
- } catch (RuntimeException | Error errorInLogging) {
+ logger
+ .get()
+ .log(
+ SEVERE,
+ String.format(Locale.ROOT, "Caught an exception in %s. Shutting down.", t),
+ e);
+ } catch (Throwable errorInLogging) { // sneaky checked exception
// If logging fails, e.g. due to missing memory, at least try to log the
// message and the cause for the failed logging.
System.err.println(e.getMessage());