Win a copy of Functional Reactive Programming this week in the Other Languages forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

No need for synchronization; there is "Lazy Initialization"

 
Harry Henriques
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is from "Effective Java" (p. 283).



Joshua Bloch wrote:When the getField method is invoked for the first time, it reads FieldHolder.field for the first time, causing the FieldHolder class to get initialized. The beauty of this idiom is that the getField method is not synchronized and performs only a field access, so lazy initialization adds practically nothing to the cost of access."


Question: The FieldHolder class is a static nested class, so doesn't the class loader load the nested class when the enclosing class is loaded? If the FieldHolder nested class is loaded when the enclosing class is loaded, then why isn't the static FieldType field initialized with an invocation of computeFieldValue( )? Can't we assume that the computeFieldValue( ) method is also a static method? Is this really "Lazy Initialization"? I don't get it?
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Harry Henriques wrote:Question: The FieldHolder class is a static nested class, so doesn't the class loader load the nested class when the enclosing class is loaded?

No. Loading (or rather, initializing) a top-level class does not automatically trigger the loading/initialization of any or all nested types within. Unless there's some other triggering event that occurs during the top-level initialization, like if your top-level class has a static field that needs to be initialized with a reference to an instance of the nested class. A precise description of the rules for this can be found here.

Harry Henriques wrote:If the FieldHolder nested class is loaded when the enclosing class is loaded, then why isn't the static FieldType field initialized with an invocation of computeFieldValue( )? Can't we assume that the computeFieldValue( ) method is also a static method? Is this really "Lazy Initialization"? I don't get it?

The initial assumptions of the question are flawed, so the remaining questions fall apart. Yes, the technique described above by Josh Bloch really is lazy initialization.
 
Mohammed Yousuff
Ranch Hand
Posts: 198
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I believe this is the same pattern used in Singleton lazy initialization, rather than a null check... is that correct?
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, that's what the book is discussing on the page Harry gave (p. 283).
 
Henry Wong
author
Marshal
Pie
Posts: 21513
84
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

To be quite honest, I don't understand the point of this technique. What makes this technique better than just using synchronization, and lazy initialization? Is it to just avoid the synchronized keyword?

So, there isn't a explicit lock being used, but... internal locks are being used (for the class loading), and it is taking an IO hit too, to load the class. How is this better?

Henry
 
Harry Henriques
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for your replies. I have a question that is related to my original question on p. 283 of "Effective Java."

http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.1

JLS 12.4.1 wrote:A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

* T is a class and an instance of T is created.
* T is a class and a static method declared by T is invoked.
* A static field declared by T is assigned.
* A static field declared by T is used and the field is not a constant variable (§4.12.4).
* T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.




paraphrase wrote:A class T will be initialized immediately before the first occurrence of the following: T is a class and an instance of T is created.


I realize that the "static" nested class FieldHolder is not instantiated in the true sense of instantiation (a "new" operator doesn't invoke its constructor). The "static" nested class FieldHolder can be instantiated using the "new" operator, but the "new" operatior isn't used and the nested class isn't instantiated (in this case) before the getField( ) method accesses the "static" field within the FieldHolder context. What exactly is happening when the getField( ) method accesses the "static" field in the Fieldholder nested class? Is an instance of the FieldHolder nested class created at this time?

Best regards,
Harry Henriques
 
Matthew Brown
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:
So, there isn't a explicit lock being used, but... internal locks are being used (for the class loading), and it is taking an IO hit too, to load the class. How is this better?

Presumably the point is that this hit is a one-off, whereas using synchronization affects all calls to the static method. Whether that's worth having a less obvious mechanism is a matter of opinion and the particular situation.
 
Harry Henriques
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Matthew,

I made a mistake in my previous observation, and edited my last response while you looked at it.

You may want to take another look at my last response after the edit. Now, I think that my question is more accurate.

Best regards,
Harry Henriques
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Harry Henriques wrote:What exactly is happening when the getField( ) method accesses the "static" field in the Fieldholder nested class? Is an instance of the FieldHolder nested class created at this time?

No FieldHolder is ever instantiated in this code. However, a static field declared by FieldHolder is used, and the field is not a constant variable. See the 4th item on the list of things that can cause a class to be initialized, which you just quoted.
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Matthew Brown wrote:
Henry Wong wrote:
So, there isn't a explicit lock being used, but... internal locks are being used (for the class loading), and it is taking an IO hit too, to load the class. How is this better?

Presumably the point is that this hit is a one-off, whereas using synchronization affects all calls to the static method. Whether that's worth having a less obvious mechanism is a matter of opinion and the particular situation.

My guess is that the JVM code to check if it needs to initialize a class is probably optimized pretty well already. That's something they need to do quite routinely, after all, whenever any of those listed events occurs. Much, much more often than synchronization is performed. So however exactly they do it, they've probably put a lot more effort into getting it to happen quickly. My guess is that in terms of performance, it's probably comparable to double-checked locking with a volatile variable. But frankly, it's a lot simpler to code. Or at least shorter - it may be more complex in that it relies on a subtle trick. But hey, if everyone just reads Effective Java, then it will be well-known, and this problem goes away.
 
Harry Henriques
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mike Simmons wrote:No FieldHolder is ever instantiated in this code.


Hi Mike,

I'm not trying to be a wise guy, but how can you initialize the static members of a static nested class that hasn't been instantiated? That's like creating a pearl without the clam.

Curious,
Harry Henriques
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, since they're static members, you don't need an instance at all to use them, or initialize them. That's pretty much what "static" means when it's used as a modifier for a field or method. Take a look at the java.lang.Math class for example - you can't instantiate it. You just call the static methods, or reference the static fields. No instances needed.
 
Harry Henriques
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mike Simmons wrote:since they're static members, you don't need an instance at all to use them, or initialize them. That's pretty much what "static" means when it's used as a modifier for a field or method.


Hi Mike,

Maybe we are getting somewhere with this line of questioning.

Since they are "static" members of the enclosing class, why isn't FieldHolder ("static" nested class) loaded/initialized when the enclosing class is loaded/initialized/instantiated?

Curious,
Harry Henriques
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wile it might seem to make intuitive sense that initializing a top-level class would trigger the initialization of its member classes, nowhere is this stated in the rules given. It's not one of the five bulleted items above. And the way the rule is phrased, anything not on the list cannot trigger class initialization, because class initialization has to happen immediately before the first event that is on the list. It's not allowed to happen earlier because of some other unlisted event.

Further, look at JLS 12.4:
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class. Initialization of an interface consists of executing the initializers for fields (constants) declared there.

Nothing about initializing member classes. Just static initializers and static fields.

Or look at the detailed initialization procedure given in JLS 12.4.2. None of those steps says anything about needing to initialize nested classes just because the top-level class is being initialized. Again, we just see static fields and static initializers getting called:
9. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block, except that final class variables and fields of interfaces whose values are compile-time constants are initialized first (§8.3.2.1, §9.3.1, §13.4.9).

So although it may make intuitive sense for everything within a top-level class to get initialized at the same time, that's not what happens. Nested classes are considered separate classes from the top-level classes that contain them.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic