Chapter 5 Notes Singleton Pattern

oralwideΔιακομιστές

17 Νοε 2013 (πριν από 3 χρόνια και 10 μήνες)

132 εμφανίσεις

1


Chap
t
er
5

Notes


Singleton

Pattern


General UML




Intent: Ensure that a class has only one instance and provide a global point of access to it.


Text Discussion


1.

How do you create a global variable in Java?

2.

Describe in your own words how the singleton
pattern can be implemented in Java (without multiple
threads).

3.

Study the singleton code on page 173 very carefully. Understand it completely. Suppose you need a
Log

class to store data about access attempts on any system mass storage device. The class shou
ld
have a
addTo

method

which adds an object to the log and a

write

method

which displays the items in
the log
. Since the log will be utilized system wide, it needs to be a singleton. Write the code for the
Log

class trying hard to rely on your memory of ho
w it works and not peeking at the text unless you
have to.


4.

On page 177, what does this mean, “...the Singleton is created in a lazy manner...?” What are the
practical implications?

5.

While we say that lazy creation is advantage
ous. But,
once the first reque
st is made, the singleton
exists forever. Suppose this singleton occupied a large amount of memory which causes a slow
-
down
in th
e system when it is not needed and o
ften, long stretches of time go by when the singleton is not
needed. Then, it may get hundr
eds of hits in a brief time. What change could you make to the classic
singleton design to help this situation?

Is there a class in the API that could help?

6.

Explain why the approach to singleton presented so far, can fail with multiple threads.

7.

Why is the
multiple threads problem a somewhat limited problem?

8.

Describe the approach to

fix the multithreading problem

on page 180.
What is the disadvantage of
this?

9.

Describe three ways to improve the multithreading singleton.

10.

Compare and contrast
volatile
and
synch
ronized.

11.

What are
static initializer blocks
?

What are they used for?

12.

We have a new design principle in the first paragraph on page 185. What is it?

13.

What are the two responsibilities that the singleton has?





2


Singleton
in Java

API


1.

Every Java application has a single instance of
the
class
java.lang.
Runtime that allows the application
to interface with the environment in which the application is running. The current runtime can be
obtained from the
getRuntime

method.




Example:



try


{


Runtime runtime = Runtime.getRuntime();


runtime.exec(
"notepad.exe"

);





System.out.println(
"num processors="

+ runtime.availableProcessors() );


System.out.println(
"avail memory="

+ r
untime.freeMemory() );


}


catch
( IOException e )


{


System.out.println(
"error"

);


}



a.

Reading an image into java:

http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter06/images.html


b.

Som
e

toolkit method examples. Can get screen size, resolution, key lock

state, clipboard:

http://www.java2s.com/Code/JavaAPI/java.awt/ToolkitgetDefaultToolkit.htm


c.

Screen Size:

http://www.roseindia.net/java/java
-
get
-
example/screen
-
dimensions.shtml


d.

Clipboard copy and past
e
:

http://www.javapractices.com/topic/TopicAction.do?Id=82




3


e.

E
ventQueue


All graphical components of the Java graphical user interface (GUI) AWT or
Swing belong to the GUI main thread. Java AWT and Swing are not thread safe, which is why it
is not permitted to access any GUI component from any thread other than the
main GUI
thread.


There are many Java GUI applications which do not work correctly, because they access a GUI
component from a second thread. As many computer
s

are single CPU computers with a single
core CPU these applications seems to work correctly but t
hey may crash without apparent
cause or reason.

Running such applications on a multi core or multi CPU machine will crash.


The solution to this kind of problem is to create user defined AWT event and store them in the
AWT event queue. The main AWT GUI thr
ead is then able to dispatch these events.



http://www.kauss.org/Stephan/swing/index.html


f.

Headless mode in Java



a system configuration when the display device, keyboard, or mouse
are not pre
sent.

http://www.oracle.com/technetwork/articles/javase/headless
-
136834.html


2.

The Singleton and AbstractFactory are sometimes used together.
Th
e
Toolkit

class is

the abstract
superclass of all actual implementations used to bind the various
GUI
components to particular native
toolkit implementations.


Most applications should not call any of the methods in this class directly. The methods defined by
Toolkit are th
e "glue" that joins the platform
-
independent classes in the java.awt package with their
counterparts in java.awt.peer. Some methods defined by Toolkit query the native operating system
directly.




4


3.

The Desktop class

is a Singleton and
allows a Java applic
ation to launch associated applications
registered on the native desktop to handle a URI or a file.

The
getDesktop

method returns the
instance.





4.

The Collections class has three m
ethods that return “singletons”, but they are not singletons in the
desig
n pattern sense. They are convenience methods to create sets/lists/maps with a single element.


http://java.sun.com/developer/onlineTraining/collections/Collection.html#SingletonCollections




Copied from:
http://java.sun.com/docs/books/tutorial/collections/implementations/convenience.html


Sometimes you'll need an immutable singleton Set, which consists of a single, specified element. The
Collections.singleton method returns such a Set. One use of this impl
ementation is to remove all
occurrences of a specified element from a Collection.


c.removeAll(Collections.singleton(e));


A related idiom removes all elements that map to a specified value from a Map. For example, suppose
you have a Map


job


that maps

people to their line of work and suppose you want to eliminate all
the lawyers. The following one
-
liner will do the deed.


job.values().removeAll(Collections.singleton(LAWYER));


One more use of this implementation is to provide a single input value to a

method that is written to
accept a collection of values.





5


Building a Singleton


1.

The classic singleton exhibits lazy instantiation. However, making the constructor private doesn’t allow
the Singleton to be subclassed. We can use the final keyword to
make this explicit.


public

final

class

Singleton

{


private

static

Singleton instance =
null
;




private

Singleton()


{
// Exists only to prevents instantiation.


}




public

static

Singleton getInstance()


{


if
(instance ==
null
)


{


instance =
new

Singleton();


}


return

instance;


}




public

void

doSomething()


{


System.out.println(
"Base Class Singleton"

);


}

}





6


2.

If we want the singleton to allow subclasses, we can make the
constructor protected.


class

Singleton

{


private

static

Singleton instance =
null
;




protected

Singleton()


{


}




public

static

Singleton getInstance()


{


if
(instance ==
null
)


{


instance =
new

Singleton();


}


return

instance;


}




public

void

doSomething()


{


System.out.println(
"Base Class Singleton"

);


}

}


3.

But, in the preceding case, i
s it really a singleton? Is this code valid?


public

class

Driver1

{


Singleton s = Sin
gleton.getInstance();




Singleton s2 =
new

Singleton();

}


No
, it is not a singleton
. Yes,
the code is valid
if Driver
1 is in the same package as the Singleton


7



4.

Thus,
a
solution is to make the constructor protected and put it in its on package.


package

maze;

public

abstract

class

MazeFactory


{


protected

static

MazeFactory uniqueInstance =
null
;



protected

MazeFactory() {}



public

abstract

void

printMaze();

}


package

maze;

public

class

EnchantedMazeFactory
extends

MazeFactory


{


public

static

MazeFactory instance()


{


if
(uniqueInstance ==
null
)


uniqueInstance =
new

EnchantedMazeFactory();



return

uniqueInstance;


}





private

EnchantedMazeFactory() {}





public

void

printMaze()

{

System.out.println(
"Enchanted Maze"

);

}

}


package

maze;

public

class

BizzareMazeFactory
extends

MazeFactory


{


public

static

MazeFactory instance()


{


if
(uniqueInstance ==
null
)


uniqueInstance =
new

BizzareMazeFactory();



return

uniqueInstance;


}




private

BizzareMazeFactory() {}




public

void

printMaze() { System.out.println(
"Bizzare Maze"

); }

}



8


Now, to test this code:


import

maze.*;


public

class

Driver1

{


public

static

void

main( String[] args )


{


MazeFactory emz = EnchantedMazeFactory.instance();




emz.printMaze();



MazeFactory bmz = BizzareMazeFactory.instance();




bmz.printMaze();




System.out.println(
"emz==bmz: "

+ (emz==bmz) );


}

}


Which produces this

output:


Enchanted Maze

Enchanted Maze

emz==bmz: true




9


5.

Although rare, the Singleton, as written is not thread safe.
If a thread is preempted at Line
3

before
the assignment is made, the
instance

variable will still be null, and another thread can subsequently
enter the if block. In that case, two distinct singleton instances will be created.


1:

if(instance == null)

2:

{

3
:

instance = new Singleton();

4
:

}


This can be simulated with

th
e following code. First, the singleton:


public

class

Singleton


{


private

static

Singleton singleton =
null
;



private

static

boolean

firstThread =
true
;



protected

Singleton() {}



public

static

Singleton getInstance()


{


if
(singleton ==
null
)


{


simulateRandomActivity();




singleton =
new

Singleton();


}


return

singleton;


}




private

static

void

simulateRandomActivity()


{


try



{


if
(firstThread)



{


firstThread =
false
;


System.out.println(
"first thread sleeping..."
);


// This nap should give the second thread enough time


// to get by the first thread.


Thread.currentThread().sleep(50
);


}


}


catch
(InterruptedException ex)


{


System.out.println(
"Sleep interrupted"
);


}


}

}





10


public

class

SingletonTest

{



private

static

Singleton singleton =
null
;



public

static

void

main( String[] args )
throws

Exception


{


singleton =
null
;



Thread threadOne =
new

Thread


(
new

SingletonTestRunnable(
"one"

)),



threadTwo =
new

Thread


(
new

SingletonTestRunnable(

"two"

));



threadOne.start(); threadTwo.start();

threadOne.join();


threadTwo.join();


}



private

static

class

SingletonTestRunnable
implements

Runnable


{


String thread;




public

SingletonTestRunnable( String thread )


{


this
.thread = thread;


}




public

void

run()


{


// Get a reference to the singleton.


Singleton s = Singleton.getInstance();


// Protect singleton member variable from

multithreaded access.



synchronized
(SingletonTest.
class
)


{


if
(singleton ==
null
)
// If local reference is null...


singleton = s;
// ...set it to the singleton


}


// Local reference must be equal to the one and

only

instance


//

of Singleton; otherwise, we have two

Singleton instances.


System.out.println(
"Thread: "

+ thread +


", singleton==instance:"

+ ( s == singleton ) );



}


}

}


OUTPUT:


ÏϧÏ
first thread sleeping...

ÏϧÏ
Thread: two,
singleton==instance: true

ÏϧÏ
Thread: one, singleton==instance: false




11


6.

This can be fixed by synchronizing the
getInstance

method:



public

synchronized

static

Singleton getInstance()


{


if
(singleton ==
null
)


{


simulateRandomActivity();


singleton =
new

Singleton();


}


return

singleton;


}


H
owever, the getInstance() method only needs to be synchronized the first time it is called.
S
ynchronization is very expensive performance
-
wise
(synchronized methods can run up to 100 times
slow
er than unsynchronized methods).


7.

We can fix this by synchronizing just the code that is critical



public

static

Singleton getInstance()


{


if
(singleton ==
null
)


{


simulateRandom
Activity();




synchronized
(Singleton.
class
)



{


singleton =
new

Singleton();


}


}


return

singleton;


}


However, the preceding code fragment is
still
not thread
-
safe. Consider the following
scenario: Thread
1 enters the synchronized block, and, before it can assign the singleton member variable, the thread is
preempted. Subsequently, another thread can enter the if block. The second thread will wait for the
first thread to finish, but we will

still wind up with two distinct singleton instances.




12


8.

One solution is to use
double
-
checked
locking



public

static

Singleton getInstance()


{


if
(singleton ==
null
)


{


simulateRandomActivity();




synchronized
(S
ingleton.
class
)



{


if
( singleton ==
null

)


singleton =
new

Singleton();


}


}


return

singleton;


}


However, double
-
checked locking is broken:

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html


9.

Another solution is to use an
eagerly
created instance as opposed to a
lazily

created instance.
One

drawback is that you have less control over the instantiation.


public

class

Singleton

{


private

static

Singleton singleton =
new

Singleton();



protected

Singleton()


{


}



public

static

Singleton getInstance()


{


return

singleton;


}

}





13


10.

Another issue that can arise is the need to specify the Singleton class at compile time. There may be
situations where there is a need to specify the class at runtime. In this case, we can use a registry.
Consider a situation where there are a
number of subclasses of Singleton and we need to be able to
specify which one at run
-
time.


import

java.util.HashMap;


public

class

Singleton

{


private

static

HashMap map =
new

HashMap();



protected

Singleton()


{


}



public

static

synchroni
zed

Singleton
getInstance(String classname)



{


if
(classname ==
null
)


throw

new

IllegalArgumentException(
"Illegal classname"
);




Singleton singleton = (Singleton)map.get(classname);




if
(singleton !=
null
)


{



return

singleton;


}


if
(classname.equals(
"Singl
e
tonSubclass_One"
))


singleton =
new

SingletonSubclass_One();


else

if
(classname.equals(
"Singl
e
tonSubclass_Two"
))


singleton =
new

SingletonSubclass_Two();




map.put(classname, singleton);




return

singleton;


}

}



Of course
, this technique is high maintenance as we have to modify the Singleton class every time we
add a new subclass.




14


11.

A better techniq
ue is to use
reflection
.


import

java.util.HashMap;


public

class

Singleton

{


private

static

HashMap map =
new

HashMap();



protected

Singleton()


{


}



public

static

synchronized

Singleton getInstance(String classname)


{


Singleton singleton = (Singleton)map.get(classname);



if
(singleton !=
null
)


{


return

singleton;


}




try



{


singleton =



(Singleton)Class.forName(classname).newInstance();



}


catch
(Clas
sNotFoundException cnf) {}


catch
(InstantiationException ie) {}


catch
(IllegalAccessException ia) {}




map.put(classname, singleton);



return

singleton;


}

}





15


12.

To enhance this approach, you should encapsulate the registry in
its own (singleton) class.


import

java.util.HashMap;


public

class

SingletonRegistry

{


public

static

SingletonRegistry REGISTRY =


new

SingletonRegistry();





private

static

HashMap map =
new

HashMap();




protected

SingletonRegistry() {}




public

static

synchronized

Object getInstance(String classname)



{


Object singleton = map.get(classname);




if
(singleton !=
null
)


{


return

singleton;


}




try



{


singleton = Class.forName(cl
assname).newInstance();


}


catch
(ClassNotFoundException cnf) {}


catch
(InstantiationException ie) {}


catch
(IllegalAccessException ia) {}




map.put(classname, singleton);




return

singleton;


}

}


13.

Another proble
m with Singletons is that different applications can be using different class loaders. In
such a case, each application will obtain a different (unique) singleton. The only solution to this is to
specify the class loader to be the one that loaded the singl
eton originally.


https://www.securecoding.cert.org/confluence/display/java/MSC07
-
J.+Prevent+multiple+instantiations+of+singleton+objects




16


14.

Finally, serialization and deserialization is a problem. For instance, if you write a singleton to an output
stream and then two diff
erent places read the input stream, you will have two instances. This can be
fixed by overriding the readResolve method:


public class Singleton implements java.io.Serializable

{

public static Singleton INSTANCE = new Singleton();


protected Singleton() {
}


private Object readResolve()




{



return INSTANCE;

}

}


However, this method is considered insecure
.


https://www.securecoding.cert.org/confluence/display/java/MSC07
-
J.+Prevent+multiple+instantiations+of+singleton+objects



17


Examples



1.

Apache Tomcat is an open source servlet container (application server)

which p
rovides a "pure Java"
HTTP web server
environment for Java code to run.

It utilizes a StringManager singleton registry to
process error messages. Error messages are catalog
ed

by the package that contains a class. It contains
a
getManager(packageName)

method

that returns a singleton from which
error information can be
obtained.


Source:
http://onjava.com/onjava/2003/08/27/singleton.html


2.

Another

real example is a component used for Credit Card Validation:


http://software.topcoder.com/catalog/c_component.jsp?comp=10515357&ver=1




3.

A
Logger

is a good example of a singleton. An application needs to log certain activities to

a disk file. If
multiple instances of the logger were allowed, then files would be overwritten.






18


References



1.

JavaWorld

-

Excellent tutorial which covers many different scenarios.

2.

Wikipedia

-

Excellent description. Discusses relation with factory method.

3.

OnJava

-

JFrame example and server error processing.

4.

MSDN

-

Excellent description. Simple counter example.

5.

DoFactory

-

Load balancer for a web farm.

6.

TopCoder

-

Dictionary
persistence

manager, Stream filter, Cre
dit card validator

7.

Sun

-

Some examples in the Java API.

8.

AllAppLabs

-

Java example of a logger.

9.

Oracle



When is a Singleton not a Singleton?