How to implement thread-safe lazy initialization?
Asked Answered
V

14

70

What are some recommended approaches to achieving thread-safe lazy initialization? For instance,

// Not thread-safe
public Foo getInstance(){
    if(INSTANCE == null){
        INSTANCE = new Foo();
    }

    return INSTANCE;
}
Vive answered 28/11, 2011 at 14:57 Comment(0)
D
71

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

Dust answered 28/11, 2011 at 15:6 Comment(4)
This will not sufice in case your new instance takes parameters. Something like new Something(a,b,c) and that a,b,c is passed through getInstance(a,b,c). In that case, you have to use the double null checking aproach as seen in wikipedia.Kikelia
@Kikelia Actually you can by having the inner class reference (private)static fields in the outer class.Clapboard
Something and Holder classes often can be merged into a single class.Justiciar
Removing the Holder makes the INSTANCE get initialized as soon as Something is initialized, removing the lazy initialization requirement of the original questionMaryrose
K
72

If you're using Apache Commons Lang, then you can use one of the variations of ConcurrentInitializer like LazyInitializer.

Example:

ConcurrentInitializer<Foo> lazyInitializer = new LazyInitializer<Foo>() {

        @Override
        protected Foo initialize() throws ConcurrentException {
            return new Foo();
        }
    };

You can now safely get Foo (gets initialized only once):

Foo instance = lazyInitializer.get();

If you're using Google's Guava:

Supplier<Foo> fooSupplier = Suppliers.memoize(new Supplier<Foo>() {
    public Foo get() {
        return new Foo();
    }
});

Then call it by Foo f = fooSupplier.get();

From Suppliers.memoize javadoc:

Returns a supplier which caches the instance retrieved during the first call to get() and returns that value on subsequent calls to get(). The returned supplier is thread-safe. The delegate's get() method will be invoked at most once. If delegate is an instance created by an earlier call to memoize, it is returned directly.

Kynan answered 22/4, 2014 at 9:56 Comment(3)
Guava lets you use lambdas and standard Supplier now: Suppliers.memoize(Foo::new)Booklet
Is there a type generic variant of this?Wattle
@EugeneA, what do you mean? These all support generics: Supplier<Foo> and ConcurrentInitializer<Foo>.Kynan
D
71

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

Dust answered 28/11, 2011 at 15:6 Comment(4)
This will not sufice in case your new instance takes parameters. Something like new Something(a,b,c) and that a,b,c is passed through getInstance(a,b,c). In that case, you have to use the double null checking aproach as seen in wikipedia.Kikelia
@Kikelia Actually you can by having the inner class reference (private)static fields in the outer class.Clapboard
Something and Holder classes often can be merged into a single class.Justiciar
Removing the Holder makes the INSTANCE get initialized as soon as Something is initialized, removing the lazy initialization requirement of the original questionMaryrose
E
37

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.

Extrinsic answered 14/5, 2015 at 20:57 Comment(8)
+1 as this is the only suggestion, which doesn't interfere with exception handling and doesn't produce a static singletonChinchy
Assuming it is OK to have more then one instances on Foo which may happen if early calls to getInstance() are heavily contended.Inconformity
any reason not to use AtomicReference::updateAndGet and check for null in the UnaryOperator<Foo> and initialize if null?Wavellite
@BenMosher sorry, I haven't caught your idea. Wouldn't it appear just another variation of static lazy initialization?Extrinsic
With updateAndGet you might end up with more created instances since it will continue trying to update the value until it was successful. However when the current value does not match the expected value, then (as commented in this answer) you can return the current value since it is already the instantiated one.Beaune
@Beaune if you include a null check in your updater, this will not happen: instance.updateAndGet(foo -> { if (foo == null) { foo = computeSth(); } return foo; });. This will not call computeSth() again if the first call failed, because foo will not be null againSomatology
@Qw3ry, you are right I overlooked the "check for null" in the comment. Though I assume that updateAndGet might have worse performance because it always performs a compareAndSet internally with the new value, even if you return the already instantiated singleton (in your example foo).Beaune
@DavidSoroko I created a version of this that does not create multiple instances.Vetavetch
A
11

The easiest way is to use a static inner holder class :

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
}
Agra answered 28/11, 2011 at 15:5 Comment(0)
W
9
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

Ware answered 28/11, 2011 at 15:0 Comment(5)
There's a mistake in there. Keep it simple.Cordalia
To quote from the linked blog "This code doesn't work in Java."Cordalia
sorry! it was my fault! I was trying to provide fast answer to easy questionWare
This is a correct and valid answer. Better source (also given in the blog article): cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.htmlDre
The Holder Idom only works on static singletons. If you want to do instance based lazy loading this is afaik the way to go.Dre
S
8

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.

Scholar answered 8/11, 2017 at 12:16 Comment(0)
Q
2

Here is one more approach which is based on one-time-executor semantic.

The full solution with bunch of usage examples can be found on github (https://github.com/ManasjyotiSharma/java_lazy_init). Here is the crux of it:

“One Time Executor” semantic as the name suggests has below properties:

  1. A wrapper object which wraps a function F. In current context F is a function/lambda expression which holds the initialization/de-initialization code.
  2. The wrapper provides an execute method which behaves as:

    • Calls the function F the first time execute is called and caches the output of F.
    • If 2 or more threads call execute concurrently, only one “gets in” and the others block till the one which “got in” is done.
    • For all other/future invocations of execute, it does not call F rather simply returns the previously cached output.
  3. The cached output can be safely accessed from outside of the initialization context.

This can be used for initialization as well as non-idempotent de-initialization too.

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

/**
 * When execute is called, it is guaranteed that the input function will be applied exactly once. 
 * Further it's also guaranteed that execute will return only when the input function was applied
 * by the calling thread or some other thread OR if the calling thread is interrupted.
 */

public class OneTimeExecutor<T, R> {  
  private final Function<T, R> function;
  private final AtomicBoolean preGuard;
  private final CountDownLatch postGuard;
  private final AtomicReference<R> value;

  public OneTimeExecutor(Function<T, R> function) {
    Objects.requireNonNull(function, "function cannot be null");
    this.function = function;
    this.preGuard = new AtomicBoolean(false);
    this.postGuard = new CountDownLatch(1);
    this.value = new AtomicReference<R>();
  }

  public R execute(T input) throws InterruptedException {
    if (preGuard.compareAndSet(false, true)) {
      try {
        value.set(function.apply(input));
      } finally {
        postGuard.countDown();
      }
    } else if (postGuard.getCount() != 0) {
      postGuard.await();
    }
    return value();
  }

  public boolean executed() {
    return (preGuard.get() && postGuard.getCount() == 0);
  }

  public R value() {
    return value.get();
  }

}  

Here is a sample usage:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

/*
 * For the sake of this example, assume that creating a PrintWriter is a costly operation and we'd want to lazily initialize it.
 * Further assume that the cleanup/close implementation is non-idempotent. In other words, just like initialization, the 
 * de-initialization should also happen once and only once.
 */
public class NonSingletonSampleB {
  private final OneTimeExecutor<File, PrintWriter> initializer = new OneTimeExecutor<>(
    (File configFile) -> {
      try { 
        FileOutputStream fos = new FileOutputStream(configFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        BufferedWriter bw = new BufferedWriter(osw);
        PrintWriter pw = new PrintWriter(bw);
        return pw;
      } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
      }
    }
  );  

  private final OneTimeExecutor<Void, Void> deinitializer = new OneTimeExecutor<>(
    (Void v) -> {
      if (initializer.executed() && null != initializer.value()) {
        initializer.value().close();
      }
      return null;
    }
  );  

  private final File file;

  public NonSingletonSampleB(File file) {
    this.file = file;
  }

  public void doSomething() throws Exception {
    // Create one-and-only-one instance of PrintWriter only when someone calls doSomething().  
    PrintWriter pw = initializer.execute(file);

    // Application logic goes here, say write something to the file using the PrintWriter.
  }

  public void close() throws Exception {
    // non-idempotent close, the de-initialization lambda is invoked only once. 
    deinitializer.execute(null);
  }

}

For few more examples (e.g. singleton initialization which requires some data available only at run-time thus unable to instantiate it in a static block) please refer to the github link mentioned above.

Quixotic answered 7/9, 2017 at 4:39 Comment(0)
W
1

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));
    }
}
Wnw answered 11/1, 2017 at 17:11 Comment(0)
C
0

Put the code in a synchronized block with some suitable lock. There are some other highly specialist techniques, but I'd suggest avoiding those unless absolutely necessary.

Also you've used SHOUTY case, which tends to indicate a static but an instance method. If it is really static, I suggest you make sure it isn't in any way mutable. If it's just an expensive to create static immutable, then class loading is lazy anyway. You may want to move it to a different (possibly nested) class to delay creation to the absolute last possible moment.

Cordalia answered 28/11, 2011 at 15:1 Comment(2)
Lazy initialization itself should be avoided unless you really need it.Chirpy
@Kaunteya Yup, a small one. But if you're hitting the static field hard, then you probably have other problems. If you add another class to make it more lazy, then you have a relatively significant initialisation hit and overhead that stays with the entire process.Cordalia
S
0

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

Sapwood answered 28/11, 2011 at 15:1 Comment(1)
simpliest way is to make the getInstance() a synchronized method.Sapwood
C
0

With Java 8 we can achieve lazy initialization with thread safety. If we have Holder class and it needs some heavy resources then we can lazy load the heavy resource like this.

public class Holder {
    private Supplier<Heavy> heavy = () -> createAndCacheHeavy();

    private synchronized Heavy createAndCacheHeavy() {

        class HeavyFactory implements Supplier<Heavy> {
            private final Heavy heavyInstance = new Heavy();

            @Override
            public Heavy get() {
                return heavyInstance;
            }
        }
        if (!HeavyFactory.class.isInstance(heavy)) {
            heavy = new HeavyFactory();
        }
        return heavy.get();
    }

    public Heavy getHeavy() {
        return heavy.get();
    }
}

public class Heavy {
    public Heavy() {
        System.out.println("creating heavy");
    }
}
Cabalism answered 4/10, 2019 at 17:47 Comment(0)
V
0

Basing this answer on @Alexsalauyou's one I thought if it could be possible to implement a solution that does not call multiple instances.

In principle my solution may be a little bit slower (very very little), but it is definitely friendlier to the processor, and the garbage collector.

The idea is that you must first use a container which could hold an "int" value PLUS the generic you want to instance.

static class Container<T> {
   final int i; 
   final T val; 
   //constructor here
}

Let this container's fields be final for concurrency purposes.

The LazyInit<T> class, must have an AtomicReference of this container.

AtomicReference<Container<T>> ref;

LazyInit must define phase processes as private static int constants:

private static final int NULL_PHASE = -1, CREATING_PHASE = 0, CREATED = 1;

private final Container<T> NULL = new Container<>(NULL_PHASE, null),
CREATING = new Container<>(CREATING_PHASE, null);

NULL and CREATING containers can be made static and upgraded to <?> to make things lighter, then one could grab them with a casting private static method.

The AtomicReference must be initialized as NULL:

private final AtomicReference<Container<T>> ref = new AtomicReference<>(getNull());

Finally the get() method would look like this:

@Override 
public T get() { 
    Container<T> prev;
    while ((prev = ref.get()).i < CREATED) {
        if (ref.compareAndSet(getNull(), getCreating())) {
            T res = builder.get();
            ref.set(new Container<>(CREATED, res));
            return res;
        }
    }
    return prev.value;
} 
Vetavetch answered 9/3, 2022 at 17:6 Comment(0)
O
-1

Try to defined the method which gets an instance as synchronized:

public synchronized Foo getInstance(){
   if(INSTANCE == null){
    INSTANCE = new Foo();
  }

  return INSTANCE;
 }

Or use a variable:

private static final String LOCK = "LOCK";
public synchronized Foo getInstance(){
  synchronized(LOCK){
     if(INSTANCE == null){
       INSTANCE = new Foo();
     }
  }
  return INSTANCE;
 }
Outcome answered 28/11, 2011 at 15:4 Comment(4)
Using a String as a lock?? (If you want to give the lock a name, make it an instance of a nested class. That was it'll even appear in stack dumps.)Cordalia
But I am using a final String varible as lock, even it appears in stack dumps, it would not have any impaction(just need make sure this lock is only used for there.).Outcome
It's an interned String - shared across the entire process nom atter where the code came from. / The dump (^Z, jstack or whatever) will just show that it is a java.lang.String and nothing more specific.Cordalia
(I notice the second piece of code has two locks. I'm not a big fan of synchronized on methods, mostly because it locks you to the public lock, but also can be overlooked as here.)Cordalia
M
-1

I know this is a java-tagged question, but Kotlin is java-adjacent :-) With, Kotlin, you simply do:

val foo by lazy { Foo() }

// use foo as you normally would, no need to dereference it or access the value with `get()`
foo.cool()

The resulting foo property is of type Foo, not a Supplier<Foo> or any other type of holder object.

This uses a feature of Kotlin's called Delegated Properties. The lazy property delegate is part of Kotlin's standard library.

Menefee answered 2/2 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.