中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

go單例怎么實現雙重檢測是否安全

發布時間:2022-03-09 13:35:02 來源:億速云 閱讀:199 作者:iii 欄目:開發技術

這篇文章主要講解了“go單例怎么實現雙重檢測是否安全”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“go單例怎么實現雙重檢測是否安全”吧!

現狀

當前有的項目直接使用Mutex鎖,有的就直接判斷nil則創建,對于前者,每次都加鎖性能差,對于后者則會出現多個實例,也就不是單例了

改進

進而想要改進一下,在這不討論餓漢和線程非安全的實現,對于go中線程安全的懶漢實現,常見兩種:

雙重檢驗sync.Once

雙重檢驗示例:

package main
 
import (
    "sync"
    "testing"
)
var (
    instance *int
    lock      sync.Mutex
func getInstance() *int {
    if instance == nil {
        lock.Lock()
        defer lock.Unlock()
        if instance == nil {
            i := 1
            instance = &i
        }
    }
    return instance
}
// 用于下邊基準測試
func BenchmarkSprintf(b *testing.B){
    for i:=0;i<b.N;i++{
        go getInstance()

是否線程安全

基于java中雙重檢驗鎖的經驗,因為jvm的內存模型,雙重檢驗鎖會出現可見性問題,可以通過 volatile解決
那么在go里會有類似問題嗎?
關鍵點在于instance變量的讀和寫是否是原子操作
這里做了個race競態檢測:

go單例怎么實現雙重檢測是否安全

可以看到20行的寫入和14行的讀取發生了競態
上例中用64位(系統是64位)的int指針表示一個實例,也說明了對于64位數據的寫入和讀取是非原子操作

我們看另一種實現:sync.Once方法

package main
 
import (
    "sync"
    "testing"
)
var (
    instance *int
    once      sync.Once
func getInstance() *int {
    once.Do(func(){
        if instance == nil {
            i := 1
            instance = &i
        }
    })
    return instance
}
func BenchmarkSprintf(b *testing.B){
    for i:=0;i<b.N;i++{
        go getInstance()
    }

實現比雙重檢驗看起來要整潔許多

race檢測結果:

go單例怎么實現雙重檢測是否安全

沒有發生競態

關于sync.Once

那么sync.Once是怎么實現的呢

看下源碼:

package sync
 
import (
   "sync/atomic"
)
type Once struct {
   done uint32
   m    Mutex
}
func (o *Once) Do(f func()) {
   if atomic.LoadUint32(&o.done) == 0 {
      o.doSlow(f)
   }
func (o *Once) doSlow(f func()) {
   o.m.Lock()
   defer o.m.Unlock()
   if o.done == 0 {
      defer atomic.StoreUint32(&o.done, 1)
      f()

可以看到sync.Once內部其實也是一個雙重檢驗鎖,但是對于共享變量(done字段)的讀和寫使用了atomic包的StoreUint32和LoadUint32方法

sync.Once使用一個32位無符號整數表示共享變量,即使是32位變量的讀寫操作都需要atomic包方法來實現原子性,更說明了go里邊指針的讀寫不能保證原子性

感謝各位的閱讀,以上就是“go單例怎么實現雙重檢測是否安全”的內容了,經過本文的學習后,相信大家對go單例怎么實現雙重檢測是否安全這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

宁蒗| 牙克石市| 安多县| 阿图什市| 和田市| 岗巴县| 揭东县| 保康县| 诸暨市| 维西| 嘉善县| 天全县| 扬州市| 宜州市| 邯郸县| 饶阳县| 德清县| 靖宇县| 新密市| 龙泉市| 东辽县| 沈阳市| 冀州市| 马边| 靖边县| 岗巴县| 永仁县| 宁陵县| 新民市| 赤水市| 长丰县| 新晃| 东兰县| 五大连池市| 铅山县| 象山县| 平凉市| 绥宁县| 黄大仙区| 五莲县| 汽车|