Q: Atomicity of class loading

G

G. Ralph Kuntz, MD

Is class loading and class variable initialization atomic?

If I have a class defined as follows:

public class X {
private static final X INSTANCE = new X();

private X() {}

public static X getInstance() {
return INSTANCE;
}
}

can I be sure that when the class loads as a result of the call
X.getInstance(),only one instance will be created?
 
T

Thomas Hawtin

public class X {
private static final X INSTANCE = new X();

private X() {}

public static X getInstance() {
return INSTANCE;
}
}

can I be sure that when the class loads as a result of the call
X.getInstance(),only one instance will be created?


Class initialisation is done with the lock for the class (X.class) held.
There are a few ways of releasing the lock: completing the
initialisation either normally or abnormally, waiting on the lock or,
IIRC, in the case of class initialisation deadlock it can be removed.

The only way to get multiple values of INSTANCE there is to load copies
of the class through multiple class loader contexts.

But you might as well make the methods of X static and ditch the
INSTANCE variable.

Tom Hawtin
 
L

Lew

Thomas said:
But you might as well make the methods of X static and ditch the
INSTANCE variable.

Unless he's designing X to be reused.

I have just read a mighty article by Daniel Savarese, "When Static Methods and
Code Collide",
<http://www.ftponline.com/javapro/2004_09/magazine/columns/proshop/>, on why
to prefer instance methods that return static variables over static methods.

In many applications it won't make much difference, but there are times when
you want the method to be overridable or configurable. Static methods carry
the disadvantages of global variables; instance methods that return static
values mitigate these disadvantages.

- Lew
 
T

Thomas Hawtin

Lew said:
Unless he's designing X to be reused.

In my experience the word "reuse" is used by the clueless to mean
speculative generalisations. That is, introducing unnecessary complexity
into code because you think perhaps one day it will be useful. It
probably wont, but it will add greatly to maintenance.
I have just read a mighty article by Daniel Savarese, "When Static
Methods and Code Collide",
<http://www.ftponline.com/javapro/2004_09/magazine/columns/proshop/>, on
why to prefer instance methods that return static variables over static
methods.

Excellent. That appears to be an article on the strategy pattern without
mentioning the strategy pattern. Top strategy for using the strategy
pattern: don't use if it's not called for.
In many applications it won't make much difference, but there are times
when you want the method to be overridable or configurable.

Only then to you use the strategy pattern. Quite possibly with a
strategy that just call the original implementation. The original
implementation with interface can be left untouched, not harming other
users.
Static
methods carry the disadvantages of global variables; instance methods
that return static values mitigate these disadvantages.

Sounds the Monostate pattern. Like the Singleton pattern, only even dafter.

Tom Hawtin
 
D

Daniel Pitts

Is class loading and class variable initialization atomic?

If I have a class defined as follows:

public class X {
private static final X INSTANCE = new X();

private X() {}

public static X getInstance() {
return INSTANCE;
}
}

can I be sure that when the class loads as a result of the call
X.getInstance(),only one instance will be created?

The short answer is no.

Two different class loaders might load the class X at different times.
And in that case you would end up with more than one instance.

A better approach would be to use dependency injection (a form of
inversion of control). Create the instance at initialization time in
the main method, for example), and pass it where it is needed.
 
E

Eric Sosman

Daniel said:
The short answer is no.

Two different class loaders might load the class X at different times.
And in that case you would end up with more than one instance.

But they will be of different classes that happen to share
a single name. Try it: load X twice with two class loaders, call
both getInstance methods, call getClass on each of the instances,
and compare the Class objects.
A better approach would be to use dependency injection (a form of
inversion of control). Create the instance at initialization time in
the main method, for example), and pass it where it is needed.

In the presence of multiple class loaders, I don't see why
this would change anything. Also, I don't see why one would
saddle every class that wants to use X with the job of writing
X's initialization code.
 
D

Daniel Pitts

Eric said:
But they will be of different classes that happen to share
a single name. Try it: load X twice with two class loaders, call
both getInstance methods, call getClass on each of the instances,
and compare the Class objects.


In the presence of multiple class loaders, I don't see why
this would change anything. Also, I don't see why one would
saddle every class that wants to use X with the job of writing
X's initialization code.
class X loaded by classloader A would indeed be "different" then classX
loaded by classloader B, however, the question was about the number of
possible instances in the VM, and I was pointing out how it is possible
to not be unique.

I think you missed the point.
Only one class is responsible for initializing the X instance. the X
class itself. And only one class (or layer, depending on how you view
it) is responsible for creating the single X instance.. The
responsible layer is the framework. Or, at the very least, the
framework could create a thread-safe singleton factory object.
 
E

Eric Sosman

Daniel said:
class X loaded by classloader A would indeed be "different" then classX
loaded by classloader B, however, the question was about the number of
possible instances in the VM, and I was pointing out how it is possible
to not be unique.

One need not introduce multiple class loaders to get this
kind of "non-uniqueness." I can create an org.esosman.Runtime
and a com.dpitts.System even though both java.lang.Runtime and
java.lang.System are singletons. In this case the coincidence
of names is disambiguated by the package; that seems to me no
different that the coincidence of "full names" being disambiguated
by class loader.

The X loaded by ClassLoader A is not the same class as the
X loaded by ClassLoader B, even if they have the same package
names and the same byte code. They are different classes, so
the existence of B's X instance does not render A's X instance
non-unique, not any more than org.esosman.Runtime threatens the
uniqueness of java.lang.Runtime.
I think you missed the point.

That's possible, of course. But I think *you* have missed
the point that two classes with identical names when loaded by
different class loaders are different classes altogether. I
haven't checked, but I'm confident that a reference to A's X
is not assignment-compatible with B's X. Try to convert either
to the other, and I think you'll get ClassCastException -- and
if an Xa can't be cast to an Xb, how can these two incompatible
entities possibly be considered duplicates?
Only one class is responsible for initializing the X instance. the X
class itself. And only one class (or layer, depending on how you view
it) is responsible for creating the single X instance.. The
responsible layer is the framework. Or, at the very least, the
framework could create a thread-safe singleton factory object.

You've shifted from "the main method, for example" to "the
framework," and somewhere along the way you've exceeded my
capacity to understand. You may be right or wrong or undecidable,
but I can't tell: I don't know what you're saying here.
 
D

Daniel Pitts

Eric said:
You've shifted from "the main method, for example" to "the
framework," and somewhere along the way you've exceeded my
capacity to understand. You may be right or wrong or undecidable,
but I can't tell: I don't know what you're saying here.

My main point was that you should usually create the objects (including
singletons) at initialization time, rather than asking the class loader
to do it. Or, if you need to use lazy loading, then create the
thread-safe factory object at initialization time.

Using dependency injection instead of static object references is a
better way to manage what objects are created for your application.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,900
Latest member
Nell636132

Latest Threads

Top