Singleton Oliver Haase HTWG Konstanz 1 / 19
Description I Classification: object based creational pattern Puropse: ensure that a class can be instantiated exactly 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 for discrete event simulation 2 / 19
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 3 / 19
Description III Alternative: Class with static variables and static methods Drawbacks: 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 4 / 19
5 / 19
Singleton implementation with Lazy Instantiation 1 public c l a s s MySingleton { 2 private s t a t i c MySingleton i n s t a n c e = n u l l ; 3 private MySingleton () { 4 5 6 public s t a t i c MySingleton 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 return instance ; 11 12 13 5 / 19
Singleton implementation with Lazy Instantiation 1 public c l a s s MySingleton { 2 private s t a t i c MySingleton i n s t a n c e = n u l l ; 3 private MySingleton () { 4 5 6 public s t a t i c MySingleton 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 return instance ; 11 12 13 Problem: Can lead to several instances if thread gets interrupted between lines 7 and 8 not thread-safe! 5 / 19
Resolve concurrency problem through synchronization: public c l a s s MySingleton { private s t a t i c MySingleton i n s t a n c e = n u l l ; private MySingleton () { public s t a t i c synchronized MySingleton 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 ( ) ; return instance ; 6 / 19
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, 2 GHz Intel Core 2 Duo, 1 GB RAM, 120 GB hard drive: unsynchronized synchronized 4 sec. 58 sec. 7 / 19
with Checked Locking 1 public c l a s s MySingleton { 2 private s t a t i c MySingleton i n s t a n c e = n u l l ; 3 private MySingleton () { 4 5 6 public s t a t i c MySingleton 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 synchronized ( MySingleton. 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 return instance ; 13 14 15 8 / 19
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! 9 / 19
Solution attempt using Double-Checked-Locking-(Anti-)Pattern: 1 public c l a s s MySingleton { 2 private s t a t i c MySingleton i n s t a n c e = n u l l ; 3 private MySingleton () { 4 5 6 public s t a t i c MySingleton 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 synchronized ( MySingleton. 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 return instance ; 15 16 17 Works well or does it? 10 / 19
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 callmysingletonconstructor ( instance ) 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 is interrupted within line 10! 11 / 19
The simple things are often the best or: Life can be that simple! fully functional, performant solution: public c l a s s MySingleton { 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 ( ) ; private MySingleton () { public s t a t i c MySingleton g e t I n s t a n c e () { return instance ; 12 / 19
Consequences of the simple implementation 13 / 19
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 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 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 1 more 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 Codeabha ngigkeiten. In HTWG Forum, 2008/2009] 14 / 19
Singleton Additional Considerations Sometimes, a singleton object needs to be configured at creation time (or at the time of first usage) Example: Socket listener that needs to listen on certain port Possible 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 ( ) ; private int state ; p r i v a t e CS1 ( ) { private void config ( int state ) { this. state = state ; 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 ) { instance. config ( state ); return instance ; params need to be passed into all subsequent getinstance calls 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 ( ) ; private int state ; p r i v a t e CS2 ( ) { private void c o n f i g ( i n t s t a t e ) { this. state = state ; 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 ) { instance. config ( state ); return instance ; p u b l i c s t a t i c CS2 g e t I n s t a n c e ( ) { return instance ; 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 ( ) ; private int state ; 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 ( ) { public synchronized void c o n f i g ( i n t s t a t e ) throws E x c e p t i o n { i f ( configured ) 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 ) ; this. state = state ; t h i s. configured = true ; p u b l i c s t a t i c CS3 g e t I n s t a n c e ( ) { return instance ; 17 / 19
Singleton Additional Considerations getinstance method without params + separate static config method, 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 ( ) ; private int state ; p r i v a t e s t a t i c bo ole an c o n f i g u r e d = f a l s e ; p r i v a t e CS4 ( ) { 18 / 19
Singleton Additional Considerations public s t a t i c synchronized void c o n f i g ( i n t s t a t e ) throws E x c e p t i o n { i f ( configured ) { 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 ) ; instance. state = state ; configured = true ; 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 E x c e p t i o n { i f (! configured ) 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 ) ; return instance ; 19 / 19