Upload
others
View
17
Download
0
Embed Size (px)
Citation preview
Design Patterns and RefactoringSingleton
Oliver Haase
HTWG Konstanz
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 1 / 19
Description I
Classification: object based creational pattern
Puropse:
ensure that a class can be instantiated exactly onceprovide 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 requestsapplication that can be started only onceglobal event queue for discrete event simulation
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 2 / 19
Description II
Structure:
Members:Singleton
responsible for creation of the instanceprovides static operation for access to the instance
Interactions: clients access singleton instance through getInstanceoperation
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 3 / 19
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
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 4 / 19
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
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 4 / 19
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s MySing le ton {2 p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;3 p r i v a t e MySing le ton ( ) {4 . . .5 }6 p u b l i c s t a t i c MySing le ton 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 MySing le ton ( ) ;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 betweenlines 7 and 8→ not thread-safe!
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 5 / 19
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s MySing le ton {2 p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;3 p r i v a t e MySing le ton ( ) {4 . . .5 }6 p u b l i c s t a t i c MySing le ton 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 MySing le ton ( ) ;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 betweenlines 7 and 8→ not thread-safe!
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 5 / 19
Implementation
Singleton implementation with Lazy Instantiation
1 p u b l i c c l a s s MySing le ton {2 p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;3 p r i v a t e MySing le ton ( ) {4 . . .5 }6 p u b l i c s t a t i c MySing le ton 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 MySing le ton ( ) ;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 betweenlines 7 and 8→ not thread-safe!
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 5 / 19
Implementation
Resolve concurrency problem through synchronization:
p u b l i c c l a s s MySing le ton {p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;p r i v a t e MySing le ton ( ) {
. . .}p u b l i c s t a t i c synchron ized MySing le ton 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 MySing le ton ( ) ;
}r e t u r n i n s t a n c e ;
}. . .
}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 6 / 19
Implementation
Problem: Only first call of getInstance needs to be synchronized:
→ unnecessary reduction of concurrency
→ synchronized Methods always slower than unsynchronized methods:
test program with 109 sequential getInstance calls on Mac Mini, 2GHz Intel Core 2 Duo, 1 GB RAM, 120 GB hard drive:
unsynchronized 4 sec.synchronized 58 sec.
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 7 / 19
Implementation
Implementation with Checked Locking
1 p u b l i c c l a s s MySing le ton {2 p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;3 p r i v a t e MySing le ton ( ) {4 . . .5 }6 p u b l i c s t a t i c MySing le ton 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 synchron ized ( MySing le ton . c l a s s ) {9 i n s t a n c e = new MySing le ton ( ) ;
10 }11 }12 r e t u r n i n s t a n c e ;13 }14 . . .15 }
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 8 / 19
Implementation
Scenario:
Thread1 gets interrupted between lines 8 and 9 → holds monitor ofMySingleton 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!
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 9 / 19
Implementation
Solution attempt using Double-Checked-Locking-(Anti-)Pattern:
1 p u b l i c c l a s s MySing le ton {2 p r i v a t e s t a t i c MySing le ton i n s t a n c e = n u l l ;3 p r i v a t e MySing le ton ( ) {4 . . .5 }6 p u b l i c s t a t i c MySing le ton 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 synchron ized ( MySing le ton . 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 MySing le ton ( ) ;11 }12 }13 }14 r e t u r n i n s t a n c e ;15 }16 . . .17 }
Works well — or does it?Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 10 / 19
Implementation
Problem: Thread scheduling happens on the level of byte code, not on theJava source code level . . . object creation in line 10
i n s t a n c e = new MySing le ton ( ) ;
is mapped to the following pseudo byte code
1 ptrMemory = a l locateMemory ( )2 ass ignMemory ( i n s t an c e , ptrMemory )3 c a l lMyS i n g l e t o nCon 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 object instance, if thread 10 isinterrupted within line 10!
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 11 / 19
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 MySing le ton {p r i v a t e s t a t i c MySing le ton i n s t a n c e = new MySing le ton ( ) ;
p r i v a t e MySing le ton ( ) {. . .
}p u b l i c s t a t i c MySing le ton 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 ;}. . .
}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 12 / 19
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 usagerather small damage
Time consumption at loading rsther than at first usage → neitherbetter nor worse, only different . . .
potential drawback: class loading order hardly predictable→ Problem, if one singleton instance is needed to create another
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 13 / 19
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 usagerather small damage
Time consumption at loading rsther than at first usage → neitherbetter nor worse, only different . . .
potential drawback: class loading order hardly predictable→ Problem, if one singleton instance is needed to create another
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 13 / 19
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 My In t e r f a c e {. . .
}
The current Joi implementation maps the Joi code to correspondingJava 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 andupdating of applications
1more informationen at http://www-home.htwg-konstanz.de/˜haase/hp/joi.html andin [von Drachenfels, Haase, Walter. Joi - eine Java–Spracherweiterung zur Reduzierungvon Codeabhangigkeiten. In HTWG Forum, 2008/2009]
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 14 / 19
Singleton – Additional Considerations
Sometimes, a singleton object needs to be configured at creation time (orat the time of first usage)Example: Socket listener that needs to listen on certain portPossible Realizations:
add parameters to getInstance method:
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 ;
}}
→ params need to be passed into all subsequent getInstance calls
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 15 / 19
Singleton – Additional Considerations
two overloaded getInstance methods 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 vo id 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 ;}
}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 16 / 19
Singleton – Additional Considerations
getInstance method without params + separate config method;catch repeated config invocations
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 boolean 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 synchron ized vo id c o n f i g ( i n t s t a t e )
throws Excep t i on {i f ( c o n f i g u r e d )
throw new Excep t i on ( ” 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 rue ;
}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 ;}
}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 17 / 19
Singleton – Additional Considerations
getInstance method without params + separate static configmethod, catch repeated and/or missing config invocations
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 boolean c o n f i g u r e d = f a l s e ;
p r i v a t e CS4 ( ) {}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 18 / 19
Singleton – Additional Considerations
p u b l i c s t a t i c synchron ized vo id c o n f i g ( i n t s t a t e )throws Excep t i on {
i f ( c o n f i g u r e d ) {throw new Excep t i on ( ” 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 rue ;
}
p u b l i c s t a t i c CS4 g e t I n s t a n c e ( ) throws Excep t i on {i f ( ! c o n f i g u r e d )
throw new Excep t i on ( ” not c o n f i g u r e d ye t ” ) ;r e t u r n i n s t a n c e ;
}}
Oliver Haase (HTWG Konstanz) Design Patterns and Refactoring 19 / 19