網站首頁 編程語言 正文
單例實現
type singleton struct{} var ( instance *singleton initialized uint32 mu sync.Mutex ) func Instance() *singleton { if atomic.LoadUint32(&initialized) == 1 { return instance } mu.Lock() defer mu.Unlock() if instance == nil { defer atomic.StoreUint32(&initialized, 1) instance = &singleton{} } return instance }
其中通用的代碼提取出來,就成了標準庫中sync.Once
的實現:
type Once struct { done uint32 m sync.Mutex } func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 0 { o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } } }
于是,使用sync.Once
重新實現單例模式
var ( instance2 *singleton once sync.Once ) func Instance2() *singleton { once.Do(func() { instance2 = &singleton{} }) return instance2 }
sync.Once源碼分析
1. lock并不會同步值
在lock和unlock之間修改值,并不會保證對其他協程是可見的,除非使用相同的Mutex加鎖,想要同步值必須使用atomic;
lock可以通過串行化,使得兩個協程的操作存在happen-before
關系,從而是的操作可見
happen-before
原則定義如下:
如果一個操作happens-before(之前發生)另一個操作,那么第一個操作的執行結果將對第二個操作可見,而且第一個操作的執行順序排在第二個操作之前。
兩個操作之間存在happens-before關系,并不意味著一定要按照happens-before原則制定的順序來執行。如果重排序之后的執行結果與按照happens-before關系來執行的結果一致,那么這種重排序并不非法。
2. Do執行一次
當第一次執行完Do
之后,done
設置成1,后面執行Do
會直接跳過
3. Once執行Do后不準copy
A Once must not be copied after first use.
sync.Once
執行完Do
后done
已經設置成1了,copy出來的once執行Do
會直接跳過
4. Do并發時阻塞
當兩個或者多個協程同時調用Do
時,先調用的協程執行,后面的協程會阻塞;
解釋:以單例使用once的實現說明,兩個協程同時調用Instance2()
,先調用的協程執行創建并拿到返回值,后調用的阻塞,
? 等到先調用的完成后再拿到返回值;
意義:這樣的好處是防止后調用的協程拿到的是nil
源碼說明:上面第二段代碼13行使用defer
,要等f()
結束才會把done
設置成1;其他協程并發調用Do
時,done==0
,
? 然后請求m.Lock()
形成阻塞
5. Do遞歸死鎖
如果Do
中的方法調用當前once的Do
會造成死鎖,原因參考上面一點(sync.Mutex.Lock()
時不可重入鎖)
- 《Go語言高級編程》
- Go1.16源碼
原文鏈接:https://blog.csdn.net/qq_22038259/article/details/128123515
相關推薦
- 2022-09-04 Apache?Kafka?分區重分配的實現原理解析_Linux
- 2022-08-20 Python?實現一個全連接的神經網絡_python
- 2022-11-09 GO?語言運行環境的基礎知識_Golang
- 2022-05-05 Tomcat使用https配置實戰教程_Tomcat
- 2022-12-12 用C語言如何打印一個等腰三角形_C 語言
- 2022-09-02 Python常用編碼的區別介紹_python
- 2023-02-17 linux?命令中的大于號、小于號的作用及代表的意思_linux shell
- 2022-10-14 Redis常見分布鎖的原理和實現_Redis
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支