1. シングルトンパターンとは何ですか
シングルトンパターンは、クラスが1つだけのインスタンスを持ち、そのインスタンスに対するグローバルなアクセスポイントを提供して取得することを保証する生成デザインパターンです。シングルトンパターンは、リソースを共有する必要がある場合や特定のインスタンスへのアクセスを制御する必要がある場合に一般的に使用されます。
2. シングルトンパターンの特性と利点
シングルトンパターンには、以下の特性と利点があります:
- クラスが 1 つのインスタンスオブジェクトを持つことを保証する
- 外部コードがインスタンスを取得するためのグローバルなアクセスポイントを提供する
- インスタンスの繰り返し作成を避け、システムリソースを節約する
3. シングルトンパターンの適用シナリオ
シングルトンパターンは、以下のような適用シナリオに適しています:
- ロガー: システム全体で 1 つのロガーがあることを保証し、重複したロギングを防止する
- データベース接続プール: 高並行環境では、シングルトンパターンを使用することでデータベース接続の頻繁な作成と破棄を回避できます
4. Golang でのシングルトンパターンの実装
Golang では、シングルトンパターンを実装する方法がいくつかあります。以下は、2 つの一般的な実装方法です。
4.1. 遅延初期化と急進初期化を使用した実装
遅延初期化は、最初に使用されたときにインスタンスオブジェクトを作成し、急進初期化はプログラムの開始時にインスタンスオブジェクトを作成します。
// 遅延初期化シングルトンパターンの実装
package singleton
type Singleton struct {
}
var instance *Singleton
func GetInstance() *Singleton {
if instance == nil {
instance = &Singleton{}
}
return instance
}
// 急進初期化シングルトンパターンの実装
package singleton
type Singleton struct {
}
var instance *Singleton = &Singleton{}
func GetInstance() *Singleton {
return instance
}
4.2. シングルトンパターンのスレッドセーフ問題
上記の遅延初期化実装方法は、マルチスレッド環境で問題が発生する可能性があります。複数のスレッドが同時に if instance == nil
条件に入ると、複数のインスタンスが作成される可能性があります。
4.3. sync.Once を使用したスレッドセーフなシングルトンパターンの実装
sync.Once
を使用すると、1 つのゴルーチンだけが初期化コードを実行するため、スレッドセーフの問題を解決できます。
// 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. sync.Mutex を使用したスレッドセーフな遅延初期化シングルトンパターンの実装
スレッドセーフな遅延初期化シングルトンパターンを実装する別の方法は、sync.Mutex
を使用してロックし、1 つのゴルーチンだけが初期化操作を実行することを保証することです。
// 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
}