core: remove a benign data race. (#2546)
This is an alternative to #2543 and it doesn't introduce volatile usage.
diff --git a/context/src/main/java/io/grpc/Context.java b/context/src/main/java/io/grpc/Context.java
index 4de2956..0f2e7fb 100644
--- a/context/src/main/java/io/grpc/Context.java
+++ b/context/src/main/java/io/grpc/Context.java
@@ -120,29 +120,30 @@
*/
public static final Context ROOT = new Context(null);
- private static Storage storage;
+ // One and only one of them is non-null
+ private static final Storage storage;
+ private static final Exception storageInitError;
- private static synchronized Storage initializeStorage() {
- if (storage != null) {
- return storage;
- }
+ static {
+ Storage newStorage = null;
+ Exception error = null;
try {
Class<?> clazz = Class.forName("io.grpc.ContextStorageOverride");
- storage = (Storage) clazz.getConstructor().newInstance();
- return storage;
+ newStorage = (Storage) clazz.getConstructor().newInstance();
} catch (ClassNotFoundException e) {
log.log(Level.FINE, "Storage override doesn't exist. Using default.", e);
+ newStorage = new ThreadLocalContextStorage();
} catch (Exception e) {
- throw new RuntimeException("Failed to initialize Storage implementation", e);
+ error = e;
}
- storage = new ThreadLocalContextStorage();
- return storage;
+ storage = newStorage;
+ storageInitError = error;
}
// For testing
static Storage storage() {
if (storage == null) {
- return initializeStorage();
+ throw new RuntimeException("Storage override had failed to initialize", storageInitError);
}
return storage;
}