1. What is Singleton Pattern
The Singleton Pattern is a creational design pattern that ensures a class has only one instance and provides a global access point to that instance for retrieval. Singleton pattern is commonly used in scenarios where resources need to be shared or access to a specific instance needs to be controlled.
2. Characteristics and Advantages of Singleton Pattern
The Singleton Pattern has the following characteristics and advantages:
- Ensures that the class has only one instance object
- Provides a global access point for external code to obtain the instance
- Avoids repeated creation of instances, saving system resources
3. Application Scenarios of Singleton Pattern
The Singleton Pattern is suitable for the following application scenarios:
- Loggers: Ensuring that there is only one logger for the entire system to prevent duplicate logging.
- Database Connection Pool: In high-concurrency environments, using the Singleton Pattern can avoid frequent creation and destruction of database connections.
4. Implementation of Singleton Pattern in Golang
In Golang, there are different ways to implement the Singleton Pattern. Below are two common implementation methods.
4.1. Implementation using Lazy Initialization and Eager Initialization
The lazy initialization creates the instance object when it is first used, while eager initialization creates the instance object when the program starts.
// Implementation of the lazy initialization Singleton Pattern
package singleton
type Singleton struct {
}
var instance *Singleton
func GetInstance() *Singleton {
if instance == nil {
instance = &Singleton{}
}
return instance
}
// Implementation of the eager initialization Singleton Pattern
package singleton
type Singleton struct {
}
var instance *Singleton = &Singleton{}
func GetInstance() *Singleton {
return instance
}
4.2. Thread Safety Issues in Singleton Pattern
The above lazy initialization implementation method may have issues in a multi-threaded environment because multiple threads may simultaneously enter the if instance == nil
condition, leading to the creation of multiple instances.
4.3. Implementing Thread-Safe Singleton Pattern using sync.Once
Using sync.Once
ensures that only one goroutine executes the initialization code, thereby solving the thread safety problem.
// Implementing thread-safe Singleton Pattern using sync.Once
package singleton
import (
"sync"
)
type Singleton struct {
}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
4.4. Implementing Thread-Safe Lazy Initialization Singleton Pattern using sync.Mutex
Another way to implement a thread-safe lazy initialization Singleton Pattern is to use sync.Mutex
to lock and ensure that only one goroutine executes the initialization operation.
// Implementing thread-safe lazy initialization Singleton Pattern using sync.Mutex
package singleton
import (
"sync"
)
type Singleton struct {
}
var instance *Singleton
var mu sync.Mutex
func GetInstance() *Singleton {
if instance == nil {
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &Singleton{}
}
}
return instance
}