Synchronized singleton
Hi guys! I`m writing a class that is by singleton pattern.
publiclass MyClass{
privatestatic MyClass my =null;
private Myclass(){
...
}
publicstatic MyClass getInstance(){
if (my==null){
my =new MyClass();
}
return my;
}
}
When the first time the method getInstance() is invoked, if two methods invoke it in the same time could this perform a colision and the different methods contain different instances of MyClass after the invokation?
[1109 byte] By [
amitteva] at [2007-10-2 17:08:08]

This will probably wok for you:
public class MyClass {
private static MyClass my = new MyClass();
private Myclass() {
//...
}
public static MyClass getInstance() {
return my;
}
}
Here is a useful article "When is a Singleton not a Singleton?" http://java.sun.com/developer/technicalArticles/Programming/singletons/index.html
yes , the given class is unsafe for a multithreaded scenario.
Now u can have two options
If you have to lazy load the singleton object(As u r doing now , creating on the need basis ) then u'll have to make the getInstance synchronised .
If u don't have requirement of lazy loading then you can create the factory object in static initializer list .
And if you want lazy loading without having to worry about syncing, you can use this pattern: public final class Singleton {
private static final class SingletonHolder {
static final Singleton instance = new Singleton();
}
public static Singleton instance() {
return SingletonHolder.instance;
}
}
The Singleton instance will not get created until you call instance(), and no syncing is necessary.
jverda at 2007-7-13 18:22:53 >

How is this functionally different from the code dubwai posted
in reply 2? It seems to me that in both cases the classloader will
load the class when it feels like it .. probably, but not assuredly,
the first time the method gets called.
I'm not arguing that it doesn't work differently, I just don't understand
*why* it works differently.
> And if you want lazy loading without having to worry
> about syncing, you can use this pattern: > public final class Singleton {
>private static final class SingletonHolder {
> static final Singleton instance = new
> ce = new Singleton();
>}
>
>public static Singleton instance() {
> return SingletonHolder.instance;
>}
> }
>
> The Singleton instance will not get created until you
> call instance(), and no syncing is necessary.
> How is this functionally different from the code
> dubwai posted
> in reply 2? It seems to me that in both cases the
> classloader will
> load the class when it feels like it .. probably,
> but not assuredly,
> the first time the method gets called.
In practice you are right but in practice there are often cases where the outer class is loaded prior to being accessed in code. For example if you were using Jython to call your class, I believe as soon as you import the class it will be loaded. Some app-servers do this kind of thing too.
> I'm not arguing that it doesn't work differently, I
> just don't understand
> *why* it works differently.
You have a good point, I'm not aware of any reason that the VM can't decide to load the inner class at an arbitrary time just like it can with the outer class. I think it just works in practice and most Java code is not developed for unknown VMs.
> How is this functionally different from the code
> dubwai posted
> in reply 2? It seems to me that in both cases the
> classloader will
> load the class when it feels like it .. probably,
> but not assuredly,
> the first time the method gets called.
>
> I'm not arguing that it doesn't work differently, I
> just don't understand
> *why* it works differently.
The outer class gets loaded as soon as it's referenced, but the neseted class won't get loaded until you call instance(), and hence, the Singleton won't get instantiated until you call intsance()--lazy instantiation.
Personally, I've never run across a case where I needed lazy instantiation of a singleton. In dubwai's code--which is how I always write singletons--the singleton instance gets created as soon as you reference the class. But that's almost always the same as when you first call instance().
The only time it would actually matter is if there were other static methods in the Singleton class that you wanted to use before calling instance(), (or maybe without ever calling instance), and instantiation is expensive or for some other reason "bad" to do before you're ready to use it.
I've never run across such a situation in practice. But if you really want lazy instantiation, that nested class is the way to do it.
jverda at 2007-7-13 18:22:53 >

> You have a good point, I'm not aware of any reason
> that the VM can't decide to load the inner class at
> an arbitrary time just like it can with the outer
> class. I think it just works in practice and most
> Java code is not developed for unknown VMs.
I thought the spec indicated that classes are loaded on demand, but I could be wrong. But yeah, like you say, even if it's not in the spec, every major VM works that way as far as I know.
jverda at 2007-7-13 18:22:53 >

Ok, thanks guys. That does clear it up for me.
>
> You have a good point, I'm not aware of any reason
> that the VM can't decide to load the inner class at
> an arbitrary time just like it can with the outer
> class. I think it just works in practice and most
> Java code is not developed for unknown VMs.
I don't believe the JLS explicitly precludes this.
It does however implicitly preclude it.
That is because if there is an exception during the load process for the inner class it can only climb the call tree from the usage (the method call.)
> I don't believe the JLS explicitly precludes this.
>
> It does however implicitly preclude it.
>
> That is because if there is an exception during the
> load process for the inner class it can only climb
> the call tree from the usage (the method call.)
I'm not sure that it precludes it. I have, on a rare occasion, caught an exception in a static block, assigned it to a class variable and thrown it from the getInstance() method. It's not elegant but I don't see why a VM couldn't use the same approach.
> I'm not sure that it precludes it. I have, on a rare
> occasion, caught an exception in a static block,
> assigned it to a class variable and thrown it from
> the getInstance() method. It's not elegant but I
> don't see why a VM couldn't use the same approach.
I think this says it can't: [url http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19175]VM Spec 2.17.2 Loading[/url]
It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
More to the point, though: [url http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19075]2.17.4 Initialization[/url] (which is when class variable intializers and static initializers will be run):
A class or interface type T will be initialized immediately before one of the following occurs:
T is a class and an instance of T is created.
T is a class and a static method of T is invoked.
A nonconstant static field of T is used or assigned.
So it seems like you can rely on the above lazy instantiation being lazy.
jverda at 2007-7-13 18:22:53 >

> > I'm not sure that it precludes it. I have, on a
> rare
> > occasion, caught an exception in a static block,
> > assigned it to a class variable and thrown it from
> > the getInstance() method. It's not elegant but I
> > don't see why a VM couldn't use the same approach.
>
> I think this says it can't: [url
> http://java.sun.com/docs/books/vmspec/2nd-edition/html
> /Concepts.doc.html#19175]VM Spec 2.17.2
> Loading[/url]
>
> It is the responsibility of a class loader,
> however, to reflect loading errors only at points in
> the program where they could have arisen without
> prefetching or group loading.
When I read that (and the adjaccent text) is says to me that if an error is thrown during group loading, you can't throw it at that point. You have to wait to throw it when the type is first used. Here's more othe text with some (I think) non-pertinent pieces removed:
In particular, a class loader may cache binary representations of
classes and interfaces, prefetch them based on expected usage, or
load a group of related classes together. ...[removed text]... It is the
responsibility of a class loader, however, to reflect loading errors only at
points in the program where they could have arisen without prefetching
or group loading
> More to the point, though: [url=http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19075]2.17.4 Initialization[/url] (which is when class
> variable intializers and static initializers will be run):
>
> A class or interface type T will be initialized
> immediately before one of the following occurs:
>
> T is a class and an instance of T is created.
>
> T is a class and a static method of T is invoked.
>
> A nonconstant static field of T is used or assigned.
>
> So it seems like you can rely on the above lazy
> instantiation being lazy.
I think you are reading into that a little. Further down it says:
The intent here is that a type have a set of initializers that put it in a
consistent state and that this state be the first state that is observed by
other classes.
It doesn't say that the intialization can't happen before any attempt is made to use the class, it just says the class must be loaded immediately (as in not a little later) before the class is used. Maybe you interpretaion is correct but it also says this:
Invocation of certain methods in library classes (?.12) also causes
class or interface initialization. See the Java 2 platform's class library
specifications (for example, class Class and package java.lang.reflect)
for details.
>
> When I read that (and the adjaccent text) is says to
> me that if an error is thrown during group loading,
> you can't throw it at that point. You have to wait
> to throw it when the type is first used.
>
That is what I see as well.
Given that doing that is going to be very hard unless someone really wants the functionality then no one is going to do it. The only possibility I could see would be in a real time device with a real time image of a process space.
> > I don't believe the JLS explicitly precludes this.
> >
> > It does however implicitly preclude it.
> >
> > That is because if there is an exception during the
> > load process for the inner class it can only climb
> > the call tree from the usage (the method call.)
>
> I'm not sure that it precludes it. I have, on a rare
> occasion, caught an exception in a static block,
> assigned it to a class variable and thrown it from
> the getInstance() method. It's not elegant but I
> don't see why a VM couldn't use the same approach.
Yes but how does the compiler keep track of the correct place where it is thrown?
And for your answer consider the impact reflection has.
> > More to the point, though:
> [url=http://java.sun.com/docs/books/vmspec/2nd-edition
> /html/Concepts.doc.html#19075]2.17.4
> Initialization[/url] (which is when class
> > variable intializers and static initializers will
> be run):
> >
> > A class or interface type T will be initialized
> > immediately before one of the following occurs:
> >
> > T is a class and an instance of T is created.
> >
> > T is a class and a static method of T is invoked.
> >
> > A nonconstant static field of T is used or
> assigned.
> >
> > So it seems like you can rely on the above lazy
> > instantiation being lazy.
>
> I think you are reading into that a little. Further
> down it says:
>
> The intent here is that a type have a set of
> initializers that put it in a
> consistent state and that this state be the first
> state that is observed by
> other classes.
>
>
> It doesn't say that the intialization can't happen
> before any attempt is made to use the class, it just
> says the class must be loaded immediately (as in not
> a little later) before the class is used.
I think if they just wanted to say "not a little later," they would have just said "before" or perhaps "no later than." The fact that they bothered to add the word "immediately" suggests to me that they want to say that it won't happen at some arbitary preceding time, that it will be the last thing that happens before any of those things occur.
I can't say for sure what the author was thinking when he wrote it, but if I were writing a VM against that spec, I would interpret that "immediately" to mean that the VM can't initialize the class before it's required.
> Maybe you
> interpretaion is correct but it also says this:
>
>
> Invocation of certain methods in library classes
> (3.12) also causes
> class or interface initialization. See the Java 2
> platform's class library
> specifications (for example, class Class and package
> java.lang.reflect)
> for details.
>
I noticed that, but I didn't follow up to find out what "certain methods" they're talking about, but I suspect that those specific cases are explicit exceptions for some particular reason, and the VM doesn't get to just decide to do that arbitarily.
jverda at 2007-7-20 23:10:57 >

> Yes but how does the compiler keep track of the> correct place where it is thrown?I'm not sure what compiler you mean here. Are you talking about JIT? Did you mean 'VM'?
> I noticed that, but I didn't follow up to find out
> what "certain methods" they're talking about, but I
> suspect that those specific cases are explicit
> exceptions for some particular reason, and the VM
> doesn't get to just decide to do that arbitarily.
It mentions class loading which I think we have established can happen at an arbitrary time. I'm not really going to argue that this is what is meant but I could take that as a green light if I were a VM implementor.
> > I noticed that, but I didn't follow up to find out
> > what "certain methods" they're talking about, but
> I
> > suspect that those specific cases are explicit
> > exceptions for some particular reason, and the VM
> > doesn't get to just decide to do that arbitarily.
>
> It mentions class loading which I think we have
> established can happen at an arbitrary time.
I haven't established that. Or rather, I don't think that initialization can happen at an arbitrary time.
> I'm not
> really going to argue that this is what is meant
Nor will argue about it anymore either. I still hold the view I stated earlier. I'm not planning on implementing a VM any time soon, and I don't have any code that relies on lazy initialization, so it's not a particularly big concern for me.
jverda at 2007-7-20 23:10:57 >

> I haven't established that. Or rather, I don't think
> that initialization can happen at an arbitrary
> time.
The VM spec states that pre-fetch loading can occur at any time and implies fairly strongly that loading can trigger initialization. If you aren't arguing against either of these, I can't see how you come to that conclusion.
> > Yes but how does the compiler keep track of the> > correct place where it is thrown?> > I'm not sure what compiler you mean here. Are you> talking about JIT? Did you mean 'VM'?Not sure what I meant now.
public class MyClass {
private static MyClass my = null;
private Myclass() {
...
}
public static MyClass getInstance() {
if (my==null) {
synchronized ( MyClass.class ) {
if ( my == null ) {
my = new MyClass();
}
}
}
return my;
}
}
Yes, what of it?
That's DCL. It won't work before 1.5. Starting with 1.5, it becomes threadsafe, but it has minimal advantage, so don't use it. Instantiate at declaration, or use the nested class lazy loading discussed above.
http://www-128.ibm.com/developerworks/library/j-jtp03304/
jverda at 2007-7-20 23:10:57 >

> That's DCL. It won't work before 1.5. Starting with 1.5, it becomes threadsafe, Only with volatile variables; the code in reply 23 will still not be threadsafe.
> > That's DCL. It won't work before 1.5. Starting with
> 1.5, it becomes threadsafe,
>
> Only with volatile variables; the code in reply 23
> will still not be threadsafe.
Yep, you're right. I just meant that DCL can work. I should have spoken more precisely.
jverda at 2007-7-20 23:10:57 >

well pardon me all over the place, I'm sure. I hereby wholly apologize for whatever the hell it is you've got a problem with, and can assure you I won't be eating any more babies or mowing down old ladies in my fast italian sports car
> I won't be> eating any more babies or mowing down old ladies in> my fast italian sports carWhy not? Although eating while driving is frowned upon, they're your own leather seats and you can do what you want in your own car.
Lokoa at 2007-7-20 23:10:57 >

> well pardon me all over the place, I'm sure. I hereby
> wholly apologize for whatever the hell it is you've
> got a problem with,
Whoa, chill out and grow a skin.
You posted something out of the blue, with no explanation, that suggested you hadn't really read the thread. I corrected it. That's all. I didn't insult your parentage or decree a fatwa demanding your head on a pole. My comments may have been blunt, but they seemed appropriate for the post I was responding to.
> and can assure you I won't be
> eating any more babies or mowing down old ladies in
> my fast italian sports car
No need to go all wimpy now.
jverda at 2007-7-20 23:11:02 >

why won't it be threadsafe? (I'm asking, not challenging, btw) I've used the DLC pattern labouring under misapprehension it was thread-safe, is the problem some quirk of the JVM? from a pure code POV, I can't see why it wouldn't work
> why won't it be threadsafe? (I'm asking, not
> challenging, btw)
>
> I've used the DLC pattern labouring under
> misapprehension it was thread-safe, is the
> problem some quirk of the JVM? from a pure code POV,
> I can't see why it wouldn't work
If you google for something like java memory model double check lock you'll find plenty of detailed explanation.
Short version:
volatile MyClass my;
public static MyClass getInstance() {
if (my==null) { // -- 1
synchronized ( MyClass.class ) {
if ( my == null ) {
my = new MyClass();// -- 2
}
}
}
return my;// -- 3
}
T1: at 1, my is null, goes on to //2
T1: at 2, puts the address of the new object in my. It's allowed to do this before the object is constructed.
T2: at 1, my is not null, goes on to 3, but T1 hasn't finished constructing the object yet.
As mentioned, the new JMM is stricter and disallows this, so starting with 5.0, this is threadsafe if the variable is volatile, but you lose some of the performance you hoped to gain with the DCL.
jverda at 2007-7-20 23:11:02 >

thanks, sounds intriguing. I've had to crash-learn Java over the last few months, so I've skimmed over a lot of intricacies such as this
> thanks, sounds intriguing. I've had to crash-learn
> Java over the last few months, so I've skimmed over a
> lot of intricacies such as this
Yeah, it's not the kind of thing one would really learn just from studying the language and APIs. This partciular nasty is due to a bug in the JMM. I first heard about it at a session at JavaOne back in around '99. It's rather well-known now, but not something you come across in you standard Java text or tutorial.
jverda at 2007-7-20 23:11:02 >
