9

I have a requirement to lazy-load resources in a concurrent environment. The code to load the resources should be executed only once.

Both Double-checked locking (using JRE 5+ and the volatile keyword) and Initialization on demand holder idiom seems to fit the job well.

Just by looking at the code, Initialization on demand holder idiom seems cleaner and more efficient (but hey, I'm guessing here). Still, I will have to take care and document the pattern at every one of my Singletons. At least to me, It would be hard to understand why code was written like this on the spot...

My question here is: Which approach s is better? And why? If your answer is none. How would you tackle this requirement in a Java SE environment?

Alternatives

Could I use CDI for this without imposing it's use over my entire project? Any articles out there?

Anthony Accioly
  • 21,918
  • 9
  • 70
  • 118

5 Answers5

7

To add another, perhaps cleaner, option. I suggest the enum variation:

What is the best approach for using an Enum as a singleton in Java?

Community
  • 1
  • 1
djg
  • 1,283
  • 9
  • 6
  • Nice. But I'm not sure I grasped how it works. Let's say `Elvis.getAge()` needs some pretty intensive operations which I want both to delay as much as possible and to execute only once. Where would I put my loading code? In the Enum constructor? – Anthony Accioly May 31 '11 at 14:58
  • @djg Sounds good enough for me. But is there a way to delay the computation even further. For example, say that I want to load several different resources independently. Using this pattern I would have to write different enums. Is there a way to achieve this with only one enum? Let's say `Elvis` with `INSTANCE1.getAge()` and `INSTANCE2.getAge()`. Could I have both of them load independently in a Thread-safe way? – Anthony Accioly May 31 '11 at 16:19
  • Right. I was thinking separate enums/singletons. If you have multiple "INSTANCE"s then your constructor gets called once for each. It was my understanding that that was undesirable. – djg May 31 '11 at 16:37
  • @djg. I think I didn't express myself well. What I mean is. What if I want `INSTANCE1.getAge()` do lazy load one value and `INSTANCE2.getAge()` to lazy load a different value? In both cases they should load it's respectively values only once (and In separate). Is it possible to achieve that behavior? (Multiple enums is fine, I'm just wondering if it can be improved). – Anthony Accioly May 31 '11 at 17:20
  • 2
    If you are handling the lazy loading (and synchronization) of the values in the method call you are circumventing the benefit of the enum singleton. I'm not sure of all of your requirements but I would suggest an interface that each of you separate singleton enum classes would implement. Or just one singleton that comprises all of the resources (presuming you can handle the "all at once" performance at load time). – djg May 31 '11 at 18:37
  • Yes, what I'm trying to avoid is the "All at once" loading. So, basically, you are telling me that it is several enums or nothing (back to manual synchronization). What I was asking if there was some manner to say, override the enum constructor for each instance (which I already know that don't work). Assuming that there is no way to do that. Why do you guys consider the enum approach cleaner than initialization on demand holder idiom? I'm not implying anything here, just asking... To me the enum approach seems just like a fancier version of the latter. What are it's benefits? – Anthony Accioly May 31 '11 at 20:05
  • That's a question of it's own. It's addressed in the link above and here: http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java – djg May 31 '11 at 20:33
  • Fair enough. Even, I'm not really worried about reflection / serialization attacks, the `Serializable` by default is an pretty ok reason by it's own. Thank you very much for your time. – Anthony Accioly May 31 '11 at 20:49
  • I still think using enums for this is semantically weird and confusing. I much prefer the IODH idiom. – Alex Miller Jun 01 '11 at 15:37
  • Anthony and Alex, that is why we created the Lazy/LazyReference classes, to encapsulate and semantically distinguish the laziness of each individual item. Additionally, IODH and enum are both static only solutions, where the lazy classes are applicable wherever you want them. – Jed Wesley-Smith Jun 02 '11 at 23:11
7

As far as readability I would go with the initialization on demand holder. The double checked locking, I feel, is a dated and an ugly implementation.

Technically speaking, by choosing double checked locking you would always incur a volatile read on the field where as you can do normal reads with the initialization on demand holder idiom.

starblue
  • 55,348
  • 14
  • 97
  • 151
John Vint
  • 39,695
  • 7
  • 78
  • 108
7

Initialisation-on-demand holder only works for a singleton, you can't have per-instance lazily loaded elements. Double-checked locking imposes a cognitive burden on everyone who has to look at the class, as it is easy to get wrong in subtle ways. We used to have all sorts of trouble with this until we encapsulated the pattern into utility class in our concurrency library

We have the following options:

Supplier<ExpensiveThing> t1 = new LazyReference<ExpensiveThing>() {
  protected ExpensiveThing create() {
    … // expensive initialisation
  }
};

Supplier<ExpensiveThing> t2 = Lazy.supplier(new Supplier<ExpensiveThing>() {
  public ExpensiveThing get() {
    … // expensive initialisation
  }
});

Both have identical semantics as far as the usage is concerned. The second form makes any references used by the inner supplier available to GC after initialisation. The second form also has support for timeouts with TTL/TTI strategies.

Jed Wesley-Smith
  • 4,686
  • 18
  • 20
  • sometimes called the Virtual Proxy pattern... The implementation nicely illustrates a solution to the "thundering herd" problem where multiple callers request the same resource but you only want to acquire the resource once. – Alex Miller Jun 01 '11 at 15:36
5

Initialization-on-demand holder is always best practice for implementing singleton pattern. It exploits the following features of the JVM very well.

  1. Static nested classes are loaded only when called by name.
  2. The class loading mechanism is by default concurrency protected. So when a thread initializes a class, the other threads wait for its completion.

Also, you don't have to use the synchronize keyword, it makes your program 100 times slower.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Ahmad
  • 2,110
  • 5
  • 26
  • 36
3

I suspect that the initialization on demand holder is marginally faster that double-checked locking (using a volatile). The reason is that the former has no synchronization overhead once the instance has been created, but the latter involves reading a volatile which (I think) entails a full memory read.

If performance is not a significant concern, then the synchronized getInstance() approach is the simplest.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • So, as far as speed goes: initialization on demand holder > Double-checked locking > synchronized method right? That's what I think too. Maybe it is time for some evil micro-benchmarking. – Anthony Accioly May 31 '11 at 16:07
  • @Anthony, thats correct. basically the demand holder achieves what you want the DCL to do without a volatile load. – John Vint May 31 '11 at 16:32
  • @Anthony - micro-benchmarking is not evil. It is just difficult to get results that are meaningful, and applicable to your real use-case. – Stephen C Jun 01 '11 at 00:42