What are some recommended approaches to achieving thread-safe lazy initialization? For instance,
// Not thread-safe
public Foo getI
Depending on what you try to achieve:
If you want all Threads to share the same instance, you can make the method synchronized. This will be sufficient
If you want to make a separate INSTANCE for each Thread, you should use java.lang.ThreadLocal
If you use lombok in your project, you can use a feature described here.
You just create a field, annotate it with @Getter(lazy=true)
and add initialization, like this:
@Getter(lazy=true)
private final Foo instance = new Foo();
You'll have to reference field only with getter (see notes in lombok docs), but in most cases that's what we need.
For singletons there is an elegant solution by delegating the task to the JVM code for static initialization.
public class Something {
private Something() {
}
private static class LazyHolder {
public static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
see
http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
and this blog post of Crazy Bob Lee
http://blog.crazybob.org/2007/01/lazy-loading-singletons.html
Thinking about lazy initialization, I would expect getting a "almost real" object that just decorates the still not initialized object.
When the first method is being invoked, the instance within the decorated interface will be initialized.
* Because of the Proxy usage, the initiated object must implement the passed interface.
* The difference from other solutions is the encapsulation of the initiation from the usage. You start working directly with DataSource
as if it was initialized. It will be initialized on the first method's invocation.
Usage:
DataSource ds = LazyLoadDecorator.create(dsSupplier, DataSource.class)
Behind the scenes:
public class LazyLoadDecorator<T> implements InvocationHandler {
private final Object syncLock = new Object();
protected volatile T inner;
private Supplier<T> supplier;
private LazyLoadDecorator(Supplier<T> supplier) {
this.supplier = supplier;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (inner == null) {
synchronized (syncLock) {
if (inner == null) {
inner = load();
}
}
}
return method.invoke(inner, args);
}
protected T load() {
return supplier.get();
}
@SuppressWarnings("unchecked")
public static <T> T create(Supplier<T> factory, Class<T> clazz) {
return (T) Proxy.newProxyInstance(LazyLoadDecorator.class.getClassLoader(),
new Class[] {clazz},
new LazyLoadDecorator<>(factory));
}
}
This can be done in lock-free manner by using AtomicReference as instance holder:
// in class declaration
private AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
Foo foo = instance.get();
if (foo == null) {
foo = new Foo(); // create and initialize actual instance
if (instance.compareAndSet(null, foo)) // CAS succeeded
return foo;
else // CAS failed: other thread set an object
return instance.get();
} else {
return foo;
}
}
Main disadvantage here is that multiple threads can concurrently instantiate two or more Foo
objects, and only one will be lucky to be set up, so if instantiation requires I/O or another shared resource, this method may not be suitable.
At the other side, this approach is lock-free and wait-free: if one thread which first entered this method is stuck, it won't affect execution of others.
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
This is called double checking! Check this http://jeremymanson.blogspot.com/2008/05/double-checked-locking.html