Design Patterns and Refactoring
Singleton
Oliver Haase
HTWG Konstanz
Description I
Classification: object based creational pattern Puropse:
ensure that a class can be instantiatedexactly once provide global access point to single instance Application Examples:
exactly one driver for a piece if hardware (e.g. printer) exactly one socket listener that receives incoming requests application that can be started only once
global event queue fordiscrete event simulation
Description II
Structure:
Members:
Singleton
responsible for creation of the instance
provides static operation for access to the instance
Interactions: clients access singleton instance through getInstance operation
Description III
Alternative: Class with static variables and static methods Drawbacks:
Java interfaces cannot contain static methods
→ class cannot be hidden behind interface each method invocation contains class name
→ undermines polymorphism
Description III
Alternative: Class with static variables and static methods
Drawbacks:
Java interfaces cannot contain static methods
→ class cannot be hidden behind interface each method invocation contains class name
→ undermines polymorphism
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s M y S i n g l e t o n {
2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {
4 . . .
5 }
6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {
8 i n s t a n c e = new M y S i n g l e t o n ( ) ;
9 }
10 r e t u r n i n s t a n c e ;
11 }
12 . . .
13 }
Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8
→ not thread-safe!
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s M y S i n g l e t o n {
2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {
4 . . .
5 }
6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {
8 i n s t a n c e = new M y S i n g l e t o n ( ) ;
9 }
10 r e t u r n i n s t a n c e ;
11 }
12 . . .
13 }
Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8
→ not thread-safe!
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s M y S i n g l e t o n {
2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {
4 . . .
5 }
6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l ) {
8 i n s t a n c e = new M y S i n g l e t o n ( ) ;
9 }
10 r e t u r n i n s t a n c e ;
11 }
12 . . .
13 }
Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8
→ not thread-safe!
Implementation
Resolve concurrency problem through synchronization:
p u b l i c c l a s s M y S i n g l e t o n {
p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; p r i v a t e M y S i n g l e t o n ( ) {
. . . }
p u b l i c s t a t i c s y n c h r o n i z e d M y S i n g l e t o n g e t I n s t a n c e ( ) {
i f ( i n s t a n c e == n u l l ) {
i n s t a n c e = new M y S i n g l e t o n ( ) ; }
r e t u r n i n s t a n c e ; }
. . . }
Implementation
Problem: Only first call of getInstance needs to be synchronized:
→ unnecessary reduction of concurrency
→ synchronized Methodsalwaysslower than unsynchronized methods:
test program with 109 sequentialgetInstance calls on Mac Mini, 2 GHz Intel Core 2 Duo, 1 GB RAM, 120 GB hard drive:
unsynchronized 4 sec.
synchronized 58 sec.
Implementation
Implementation with Checked Locking
1 p u b l i c c l a s s M y S i n g l e t o n {
2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {
4 . . .
5 }
6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l) {
8 s y n c h r o n i z e d ( M y S i n g l e t o n .c l a s s ) { 9 i n s t a n c e = new M y S i n g l e t o n ( ) ;
10 }
11 }
12 r e t u r n i n s t a n c e ;
13 }
14 . . .
15 }
Implementation
Scenario:
Thread1 gets interrupted between lines 8 and 9 → holds monitor of MySingleton class object, no singleton instance created yet.
Thread2 passes 7, waits at 8 for Thread1
Thread1 finishes, creates singleton instance
Thread2 finishes, creates second ‘singleton’ instance
→ not thread-safe!
Implementation
Solution attempt usingDouble-Checked-Locking-(Anti-)Pattern:
1 p u b l i c c l a s s M y S i n g l e t o n {
2 p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = n u l l; 3 p r i v a t e M y S i n g l e t o n ( ) {
4 . . .
5 }
6 p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { 7 i f ( i n s t a n c e == n u l l) {
8 s y n c h r o n i z e d ( M y S i n g l e t o n .c l a s s ) {
9 i f ( i n s t a n c e == n u l l ) {
10 i n s t a n c e = new M y S i n g l e t o n ( ) ;
11 }
12 }
13 }
14 r e t u r n i n s t a n c e ;
15 }
16 . . .
17 }
Implementation
Problem: Thread scheduling happens on the level of byte code, not on the Java source code level . . . object creation in line 10
i n s t a n c e = new M y S i n g l e t o n ( ) ;
is mapped to the following pseudo byte code
1 ptrMemory = a l l o c a t e M e m o r y ( ) 2 a s s i g n M e m o r y ( i n s t a n c e , ptrMemory ) 3 c a l l M y S i n g l e t o n C o n s t r u c t o r ( i n s t a n c e )
If scheduling takes place between lines 2 and 3 then instance != null, even though
instance has not been properly initialized
⇒ Thread2 might return uninitialized objectinstance, if thread 10 is interrupted withinline 10!
Implementation
The simple things are often the best— or: Life can be that simple!
→ fully functional, performant solution:
p u b l i c c l a s s M y S i n g l e t o n {
p r i v a t e s t a t i c M y S i n g l e t o n i n s t a n c e = new M y S i n g l e t o n ( ) ;
p r i v a t e M y S i n g l e t o n ( ) { . . .
}
p u b l i c s t a t i c M y S i n g l e t o n g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;
} . . . }
Implementation
Consequences of the simple implementation
Singleton instance is created (exactly once) at class loading time even if it will never be used→ but:
this rarely happens because class loading is usually triggered by usage rather small damage
Time consumption at loading rsther than at first usage → neither better nor worse, only different . . .
potential drawback: class loading order hardly predictable
→ Problem, if one singleton instance is needed to create another
Implementation
Consequences of the simple implementation
Singleton instance is created (exactly once) at class loading time even if it will never be used→ but:
this rarely happens because class loading is usually triggered by usage rather small damage
Time consumption at loading rsther than at first usage → neither better nor worse, only different . . .
potential drawback: class loading order hardly predictable
→ Problem, if one singleton instance is needed to create another
Usage
Joi 1 programming language supports singleton pattern:
s i n g l e t o n component MyComponent p r o v i d e s M y I n t e r f a c e { . . .
}
The current Joi implementation maps the Joi code to corresponding Java code.
Reason: Joi doesn’t support static class members
→ static variables are modelled as members of a singleton class
→ frequent usage of the singleton pattern
Java Webstart: Technology for the dynamic download, execution and updating of applications
1more informationen at http://www-home.htwg-konstanz.de/˜haase/hp/joi.html and in [von Drachenfels, Haase, Walter.Joi - eine Java–Spracherweiterung zur Reduzierung von Codeabh¨angigkeiten. In HTWG Forum, 2008/2009]
Singleton – Additional Considerations
Sometimes, a singleton object needs to be configuredat creation time (or at the time of first usage)
Example: Socket listener that needs to listen on certain port Possible Realizations:
add parameters to getInstancemethod:
p u b l i c c l a s s CS1 {
p r i v a t e s t a t i c CS1 i n s t a n c e = new CS1 ( ) ; p r i v a t e i n t s t a t e ;
p r i v a t e CS1 ( ) {}
p r i v a t e v o i d c o n f i g (i n t s t a t e ) { t h i s. s t a t e = s t a t e ;
}
p u b l i c s t a t i c CS1 g e t I n s t a n c e (i n t s t a t e ) { i n s t a n c e . c o n f i g ( s t a t e ) ;
r e t u r n i n s t a n c e ; }
}
Singleton – Additional Considerations
two overloadedgetInstancemethods with and w/o parameters
p u b l i c c l a s s CS2 {
p r i v a t e s t a t i c CS2 i n s t a n c e = new CS1 ( ) ; p r i v a t e i n t s t a t e ;
p r i v a t e CS2 ( ) {}
p r i v a t e v o i d c o n f i g (i n t s t a t e ) { t h i s. s t a t e = s t a t e ;
}
p u b l i c s t a t i c CS2 g e t I n s t a n c e (i n t s t a t e ) { i n s t a n c e . c o n f i g ( s t a t e ) ;
r e t u r n i n s t a n c e ; }
p u b l i c s t a t i c CS2 g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;
} }
Singleton – Additional Considerations
getInstancemethod without params + separateconfigmethod;
catch repeatedconfiginvocations
p u b l i c c l a s s CS3 {
p r i v a t e s t a t i c CS3 i n s t a n c e = new CS3 ( ) ; p r i v a t e i n t s t a t e ;
p r i v a t e b o o l e a n c o n f i g u r e d = f a l s e; p r i v a t e CS3 ( ) {}
p u b l i c s y n c h r o n i z e d v o i d c o n f i g (i n t s t a t e ) t h r o w s E x c e p t i o n {
i f ( c o n f i g u r e d )
throw new E x c e p t i o n ( ” a l r e a d y c o n f i g u r e d ” ) ; t h i s. s t a t e = s t a t e ;
t h i s. c o n f i g u r e d = t r u e; }
p u b l i c s t a t i c CS3 g e t I n s t a n c e ( ) { r e t u r n i n s t a n c e ;
}
Singleton – Additional Considerations
getInstancemethod without params + separate staticconfig method, catch repeated and/or missingconfiginvocations
p u b l i c c l a s s CS4 {
p r i v a t e s t a t i c CS4 i n s t a n c e = new CS4 ( ) ; p r i v a t e i n t s t a t e ;
p r i v a t e s t a t i c b o o l e a n c o n f i g u r e d = f a l s e; p r i v a t e CS4 ( ) {}
Singleton – Additional Considerations
p u b l i c s t a t i c s y n c h r o n i z e d v o i d c o n f i g (i n t s t a t e ) t h r o w s E x c e p t i o n {
i f ( c o n f i g u r e d ) {
throw new E x c e p t i o n ( ” a l r e a d y c o n f i g u r e d ” ) ; }
i n s t a n c e . s t a t e = s t a t e ; c o n f i g u r e d = t r u e; }
p u b l i c s t a t i c CS4 g e t I n s t a n c e ( ) t h r o w s E x c e p t i o n { i f ( ! c o n f i g u r e d )
throw new E x c e p t i o n ( ” n o t c o n f i g u r e d y e t ” ) ; r e t u r n i n s t a n c e ;
} }