Can we get a painless lazy loading of a Java member in the same way we can with static singles?

When doing lazy initialization of static singleton code in Java, you can do this:

public class Bob { private static class SingletonWrapper { private static final Bob instance = new Bob(); } public static Bob getInstance() { return SingletonWrapper.instance; } } 

Since the inner class SingletonWrapper loaded only when Bob() is first called, it is not created until getInstance() called.

My question is whether there are similar tricks that can be used to lazily create a member variable in an unsteady context.

 public class Bob { // Clearly this doesn't work as not lazy private final InnerWrapper wrapper = new InnerWrapper(); private class InnerWrapper { private final Jane jane = new Jane(); } public Jane getJane() { return wrapper.jane; } } 

Is there a way to have a Jane instance inside Bob and the thread is safe to have an instance created only on demand without using double check or AtomicReference . Ideally, the get method should remain as simple as in the examples above, but if this is not possible, then it would be the simplest and fastest (most efficient) execution of the get method.

+7
java lazy-loading
source share
2 answers

No, there are no synchronization rules for instance types, for example, to initialize classes. You must add them yourself. Regardless of whether you are doing this with double checked locking or some other mechanism, you can.

Starting with Java 8, I want to use ConcurrentHashMap#computeIfAbsent to achieve laziness.

 class Bob { private final ConcurrentHashMap<String, Jane> instance = new ConcurrentHashMap<>(1); public Jane getJane() { return instance.computeIfAbsent("KEY", k -> new Jane()); // use whatever constant key } } 

There are also these solutions for lazy initialization without limiting thread safety. I could not easily adapt them for a multi-threaded context.

As pointed out in the comments, a double checked lock will always be faster than these solutions, since they do not include all the fluff to hide the implementation.

+8
source share

You can use the Guava cache:

 public class Bob { private final static Object KEY = new Object(); private final Cache<Object, Jane> cache = CacheBuilder.newBuilder() .build(new CacheLoader<Object, Jane>() { @Override public Jane load() { return new Jane(); } }); public Jane getJane() { return cache.get(KEY); } } 
+2
source share

All Articles