Golang中的同步工具Sync.Once詳解
sync.Once
sync.Once是Golang標準庫中的一個同步工具,作用是保證指定函數只被執行一次,可以用于并發安全的單次初始化、單次執行等場景。
使用方法和示例
sync.Once的實現原理是基于原子性操作和鎖的機制,只有一個方法Do(f func()),在第一次調用Do時,會執行函數f并將once對象標記為已完成;第二次及以后調用Do時,將不再執行函數f。看個例子:
package main
import (
"fmt"
"sync"
)
func main() {
var once sync.Once
onceBody := func() {
fmt.Println("只執行一次")
}
done := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
once.Do(onceBody)
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
}
本例中開啟了10個goroutine,每個goroutine中都調用了once.Do(onceBody),但onceBody方法只執行了一次。
sync.Once內部使用了一個bool類型的標志位,記錄了對應函數是否已經被執行過。當Do方法第一次被調用時,該方法會獲取鎖并檢查標志位,如果標志位為false,則執行函數并將標志位設置為 true,否則直接返回鎖并退出。通過原子性的CAS操作進行設置和讀取,保證并發的正確性。
假如想要實現一個對象的延遲初始化,只有在第一次被訪問時才進行初始化操作,可以使用sync.Once來實現,代碼如下:
type MyObject struct {
// 懶加載初始化參數
initParams string
// 初始化后的值
value string
// once對象
once sync.Once
}
// 初始化函數,只被調用一次
func (o *MyObject) init() {
o.value = "initialized with " + o.initParams
}
// 獲取對象的value字段,如果對象還沒有初始化,則初始化之后再返回
func (o *MyObject) Value() string {
o.once.Do(o.init)
return o.value
}
使用了sync.Once實現了對象的懶加載,保證了并發訪問的安全性和初始化只被執行一次。當第一個goroutine調用Value方法時,會執行init函數,初始化MyObject的value字段,并標記MyObject對象的once已經執行過。后續的其他goroutine再調用Value方法時,直接返回value字段,不再進行初始化。