2

By using a volatile boolean that is read only if the instance is null, can I avoid the default/frequent volatile read once the instance is initailized like so? Havent seen anyone recommend double checked locking like this, but seems to avoid volatile reads once fully initialized...

public class Singleton {

   private static volatile boolean initialized = false;
   private static Object lock = new Object();
   private static Singleton instance;

      public static Singleton getInstance(){
           if(instance != null) return instance;
           if(!initialized){
                synchronized(lock){
                   if(!initialized){
                       instance = new Singleton();
                       initialized = true;
                   }
                }
           }
           return instance;

       }

}

S-C
  • 1,909
  • 1
  • 16
  • 14

4 Answers4

5

No, you cannot. If thread A has reached the synchronized block and is executing the

instance = new Singleton();

line, a thread B entering your function could see instance as initialized before thread A has finished constructing the object. So you risk having thread B try to work on a partially constructed object.

See the DLCP article for variations and explanations on this pattern.

Mat
  • 202,337
  • 40
  • 393
  • 406
1

Your optimization attempt is not only premature, but also fruitless, quoting Are volatile variable 'reads' as fast as normal reads?:

On an x86, there is no additional overhead associated with volatile reads.

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
0

If you want lazy instantiation but concerned about performance, use "inner class" approach - it is cleaner and shorter (and a tiny bit more efficient as well). Something like that:

public class Singleton {

    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }

}

The trick is that instance is created during initialization of the inner class - that will happen when class is first referenced, which is first call to getInstance(). BTW - avoid such "static" singletons, unless there are truly good reasons to use them.

Andrey Nudko
  • 697
  • 5
  • 5
  • inner class is actually worse as volatile read is practically free. inner class just increases the boot load time and creates useless stuff in the perm gen + extra boiler plate code. – bestsss Nov 21 '11 at 14:01
  • @bestss - unless only several classes and not 95% of your code are singletons perm gen is not an issue; and why should boot time be longer when using typical synchronized block? Also - do you think that double locking is lesser bit of boilerplate code? – Andrey Nudko Nov 21 '11 at 18:08
  • I tend to have something like LazyReference that takes a Callable in the c-tor and that's it, you can't do that with an explicit class to provide a static final field. The boot time is longer b/c the class has to be loaded off the disk (decompressed, verified etc). It's an extra call to the classloader which tends to result in looking up parent+system and bootstrap classloaders etc. – bestsss Nov 21 '11 at 18:23
  • Of course, you can argue that simplifying the code w/ Callable addes another class :D – bestsss Nov 21 '11 at 18:30
  • @bestsss - ah, that's nice; isolates "singleton" aspect from construction of the class. I also tried some benchmarks - `getInstance()` with "inner class" approach takes ~50% less time than with "double locking", but in absolute figures it's just some nanoseconds. So yeah, `LazyReference` looks attractive. – Andrey Nudko Nov 23 '11 at 09:42
  • side note on dedicated class to initialization: if any exception is thrown that would result in ExceptionInInitializerError basically preventing any attempt to re-try the operation. The only way to recover is some hot redeploy, i.e. abandoning the classloader. Usually if there is no chance to fail the initialization, it'd be better off w/ eager one. – bestsss Nov 27 '11 at 11:45
  • @bestsss - that's a valid concern, but there are not only web apps in this world; sometimes fail-fast behaviour is not so bad. – Andrey Nudko Nov 29 '11 at 20:54
  • I do not get the web page remark. I am doing a lot middleware, though – bestsss Nov 29 '11 at 21:06
0

volatile read is (almost) free on most hardware, volatile write is expensive, though... So why bother?

The short answer is no. between instance = new Singleton() and initialized = true on a weak memory model where stores can be reordered a reader might see an uninitialized Signleton. on x86 and sparc TSO no store-store reorder but on ARM and IA64 it does happen.

bestsss
  • 11,796
  • 3
  • 53
  • 63