singleton questions
Assume i have following code:
public class Manager {
private static Manager m = new Manager();
public static Manager getInstance() {
return m;
}
private Manager() {
loadConfiguration();
}
private void loadConfiguration() {
// lengthy code loading process here
}
}
If two threads access getInstance(). The first one that invokes getInstance() will make static field "m" be assigned Manager object, and the loadConfiguration() will be eventually called. Now the second thread also calls getInstance(), while loadConfiguration() is still not completed, does second thread get singleton "m" back right away or the call is automatically blocked until loadConfiguration() is finished?
If it get single instance back right away, the state of Manager object is definitely incorrect because it is still loading ...
Please someone there explains what will happen.
Thanks
Gary
[975 byte] By [
Akuwaa] at [2007-11-26 18:43:45]

# 1
Yes, you don't get the correct instance.You would like to synchronize your getInstance() method to avoid this unexpected behavior
# 2
> Assume i have following code:
>
> public class Manager {
> private static Manager m = new Manager();
It's a good idea to make 'm' final as well to prevent accidental re-assignment.
>
> public static Manager getInstance() {
>return m;
>
>
> private Manager() {
>loadConfiguration();
>}
>private void loadConfiguration() {
> // lengthy code loading process here
>
> }
>
> If two threads access getInstance(). The first one
> that invokes getInstance() will make static field "m"
> be assigned Manager object, and the
> loadConfiguration() will be eventually called.
No. The static field 'm' is assigned when the Manager class is loaded. This must happen before getInstance() can ever be called.
> Now
> the second thread also calls getInstance(), while
> loadConfiguration() is still not completed, does
> second thread get singleton "m" back right away or
> the call is automatically blocked until
> loadConfiguration() is finished?
>
> If it get single instance back right away, the state
> of Manager object is definitely incorrect because it
> is still loading ...
>
> Please someone there explains what will happen.
Class loading is a synchronized operation. Since the first thread holds the lock on the Manager class until class initialization is complete, the second thread must wait. The 'm' variable will be assigned exactly once and loadConfiguration() will have completed before any thread can call getInstance().
Jim S.
# 3
Thanks for all answers.
My last statement in question "If it get single instance back right away, the state of Manager object is definitely incorrect because it is still loading ..." is incorrect. I should say "if second thread calls getInstance(), it will get single instance variable "m" back right away but it is still null becaus the loading is not finish yet". Is this statement correct?
Actually i think if we create singleton in getInstance() method, which is synchronized, the whole thing should be understood for easily and clearly. Such as this:
.............
private static Manager m = null;
public static synchronized Manager getInstance(){
if ( m == null)
m = new Manager();
return m;
}
This is my usual way to create singleton object. Now see some code creates singleton in declare line and getInstance() has no "synchronized", and then start thinking what the consequence is if it is in multithreading environment. Just get kind of confused.
Jim is definitely righ about the "m" is assigned only when loading is finished. But i am just not very familiar with the classload synchronization. Seems Jim said the second thread will be clocked when calling getInstance() util object construction is finished (so "m" is assigned reference to the Manager.
Gary
# 4
> Thanks for all answers.
>
> My last statement in question "If it get single
> instance back right away, the state of Manager object
> is definitely incorrect because it is still loading
> ..." is incorrect. I should say "if second thread
> calls getInstance(), it will get single instance
> variable "m" back right away but it is still null
> becaus the loading is not finish yet". Is this
> statement correct?
No. It is *impossible* to call getInstance() from any thread and not receive a fully constructed Manager object. The object is constructed as part of class initialization, and class initialization must be completed before any methods of the class can be called by other objects. When a thread does something that causes a class to be initialized, the thread acquires the lock of the class object. It does not release the lock until the class has been fully initialized.
>
> Actually i think if we create singleton in
> getInstance() method, which is synchronized, the
> whole thing should be understood for easily and
> clearly. Such as this:
>
>.............
>
>private static Manager m = null;
> public static synchronized Manager getInstance()
>{
> if ( m == null)
> m = new Manager();
>return m;
>
This is known as 'lazy initialization'. It is another valid way to implement the singleton pattern.
>
> This is my usual way to create singleton object. Now
> see some code creates singleton in declare line and
> getInstance() has no "synchronized",
Lazy initialization is useful if the Manager object is resource or memory intensive and there is a chance that it will *not* be needed by the application. The synchronization of getInstance() will decrease performance if the method is called frequently by multiple threads.
If the Manager object is not resource or memory intensive, is always going to be needed by the application, or will be called frequently from multiple threads, then lazy initialization is typically not the correct approach.
> and then start
> thinking what the consequence is if it is in
> multithreading environment. Just get kind of
> confused.
>
> Jim is definitely righ about the "m" is assigned only
> when loading is finished. But i am just not very
> familiar with the classload synchronization. Seems
> Jim said the second thread will be clocked when
> calling getInstance() util object construction is
> finished (so "m" is assigned reference to the
> Manager.
Here is a simple example. It has a Manager object , implemented as a Singleton without lazy initialization, with an initialize() method that simple goes to sleep for ten seconds. Two threads A and B attempt to call getInstance() and print out the String representation of the Manager instance. When you run the code, you will see that there is a ten second pause before any output is printed, and that both threads print out the same result which means that both Threads received the *same* Manager object as a result of calling getInstance().
=====================
public class SingletonTest {
SingletonTest() {
Thread a = new Thread(new Runnable() {
public void run() {
System.out.println(Manager.getInstance());
}
});
Thread b = new Thread(new Runnable() {
public void run() {
System.out.println(Manager.getInstance());
}
});
a.start();
b.start();
}
public static void main(String[] args) {
new SingletonTest();
}
}
class Manager {
private int id = 0;
private static final Manager m = new Manager();
private Manager() {
initialize();
}
public static Manager getInstance() {
return m;
}
private void initialize() {
id++;
try {
Thread.sleep(10000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public String toString() {
return "Manager: " + id;
}
}
# 5
Thanks very much for your very clear explaination. I am pretty much convinced that method is accessible only all class loading is done, which includes any static variable receives valid reference if the object is created inline. So "synchronization" is not needed if we decide that we do not need lazy creation.
Gary
# 6
> Thanks very much for your very clear explaination. I
> am pretty much convinced that method is accessible
> only all class loading is done, which includes any
> static variable receives valid reference if the
> object is created inline. So "synchronization" is not
> needed if we decide that we do not need lazy
> creation.
>
> Gary
true, plus you should avoid using lazy creation considering that DCL is broken.
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
♠
# 7
Nothing wrong with lazy instantiation. Just synchronize your getter instead of doing DCL. Or ensure you're running on a platform where DCL works.
# 8
public class Manager {
private static Manager m ;
public static Manager getInstance() {
//double locking
if(m==null)
{
synchronized((Class.Manager)
{
if(m==null)
{
m= new Manager();
}
}
}
return m;
}
private Manager() {
loadConfiguration();
}
private void loadConfiguration() {
// lengthy code loading process here
}
}