Once使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main
import (
    "fmt"
    "sync"
)
func main() {
	var once sync.Once
// 第一个初始化函数
    f1 := func() {
    	fmt.Println("in f1")
    }
	once.Do(f1) // 打印出 in f1
	// 第二个初始化函数
	f2 := func() {
		fmt.Println("in f2")
	}
	once.Do(f2) // 无输出
}

总结一下 Once 并发原语解决的问题和使用场景:Once 常常用来初始化单例资源,或者 并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资源。

使用 Once 可能出现的 2 种错误

第一种错误:死锁 你已经知道了 Do 方法会执行一次 f,但是如果 f 中再次调用这个 Once 的 Do 方法的话, 就会导致死锁的情况出现。这还不是无限递归的情况,而是的的确确的 Lock 的递归调用导 致的死锁。

1
2
3
4
5
6
7
8
func main() {
    var once sync.Once
    once.Do(func() {
        once.Do(func() {
            fmt.Println("初始化")
        })
    })
}