场景

典型应用场景就是执行仅需执行一次的任务。例如,数据库连接池的初始化任务。又例如,一些心跳检测之类的实时监测任务。等等。

知识点

  1. 拥有一个 Do 的方法,该类型的方法Do可以接受一个无参数、无结果的函数值作为其参数。该方法一旦被调用,就会调用被作为参数传入的那个函数。且该方法只会运行一次。
  2. 内部通过 Mutex 和 atomic 实现线程安全。

栗子

1. 普通使用
  1. func main() {
  2. var once sync.Once
  3. once.Do(func() { fmt.Println("Once!") })
  4. once.Do(func() { fmt.Println("Once!") })
  5. fmt.Println("run ok")
  6. }
  7. 结果:
  8. Once!
  9. run ok

2. 单例模式
  1. //Singleton 是单例模式类
  2. type Singleton struct{}
  3. var singleton *Singleton
  4. var once sync.Once
  5. //GetInstance 用于获取单例模式对象
  6. func GetInstance() *Singleton {
  7. once.Do(func() {
  8. singleton = &Singleton{}
  9. })
  10. return singleton
  11. }
  1. const parCount = 100
  2. func TestSingleton(t *testing.T) {
  3. ins1 := GetInstance()
  4. ins2 := GetInstance()
  5. if ins1 != ins2 {
  6. t.Fatal("instance is not equal")
  7. }
  8. }
  9. func TestParallelSingleton(t *testing.T) {
  10. wg := sync.WaitGroup{}
  11. wg.Add(parCount)
  12. instances := [parCount]*Singleton{}
  13. for i := 0; i < parCount; i++ {
  14. go func(index int) {
  15. instances[index] = GetInstance()
  16. wg.Done()
  17. }(i)
  18. }
  19. wg.Wait()
  20. for i := 1; i < parCount; i++ {
  21. if instances[i] != instances[i-1] {
  22. t.Fatal("instance is not equal")
  23. }
  24. }
  25. }