目錄導航
- 1.單例模式
- 1)什么是單例模式
- 2)使用場景
- 3)實現方式
- 1.懶漢式單例模式
- 2.餓漢式
- 3.雙重檢查式
- 4.`sysc.Once`式
- 4)實踐案例
- 5)優缺點分析
1.單例模式
1)什么是單例模式
單例模式(Singleton Pattern)是一種常用的設計模式。單例模式的類提供了一種訪問其唯一對象的方法,該對象可以直接訪問,無須實例化。單例模式保證了一個類的對象只存在一個,同時維護一個對其對象的全局訪問點。
uml類圖:
2)使用場景
- 如果開發者想要更加嚴格地控制全局變量,則可以使用單例模式。單例模式可以保證一個類只存在一個實例。除了單例模式外,無法通過其他方式替換緩存的實例
- 如果程序中的某個類對于所有客戶端都只有一個可用的實例,則可以使用單例模式。在單例模式中,如果對象已經被創建,則返回已有的對象
- 在設計數據庫連接池時,可以使用單例模式。在數據庫管理系統中使用數據庫連接池,主要目的是節省打開或關閉數據庫連接引起的效率損耗。這種效率上的損耗還是非常巨大的,如果使用單例模式來進行維護的話,則可以大大減少這中類似的損耗。
3)實現方式
在golang中,單例模式的實現方式有4中,分別是懶漢式、餓漢式、雙重檢查式、和sysnc.Once。而這四種單例模式都有一個共同的特征:只實例化一次,只允許一個實例存在。
1.懶漢式單例模式
懶漢式單例模式指的是在創建對象時,不直接創建對象,在加載配置文件時才創建對象。
package typesofSigtonimport "sync"type singleton struct{value int
}
//聲明私有指令
var instance *singleton
//加鎖的目的是保證協成并發安全
//mo1.聲明鎖對象
var mutex sync.Mutex
//獲取單例對象
func GetInstance() *singleton {//加鎖,保證協成安全mutex.Lock()defer mutex.Unlock()if instance==nil{instance=new (singleton)}return instance
}
以上代碼通過加鎖的方式保證了協成的并發安全但是代碼有一個問題就是每次調用該方法都需要進行加鎖的操作,在性能上則不夠高效。
2.餓漢式
餓漢式是指,在創建對象時,不判斷創建的對象是否為空,直接創建對象。餓漢式是并發安全的,其唯一的缺點是在導入包的同時會創建對象,并且創建的對象會持續存儲于內存當中。餓漢式單例模式可以使用初始化init()函數實現
package typesofSigtonimport "fmt"//var instance *singleton
func init(){if instance==nil{instance=new(singleton)fmt.Println("創建單個實例")}
}//編寫提供實力的函數
func GetInstance() *singleton {return instance
}
3.雙重檢查式
在懶漢式的基礎上進行優化,減少加鎖的操作,這樣可以在保證并發安全的同時不影響性能,這種模式也被稱為雙重檢查單例模式
package typesofSigtonimport ("fmt""sync"
)
//聲明鎖對象
var mutex sync.Mutex
//當對象為空時,對對象進行加鎖操作;在創建好對象后,在獲取對象時就不用加鎖了
func GetIntance() *singleton{if instance ==nil{mutex.Lock()if instance==nil{instance=new(singleton)fmt.Println("創建單個實例")}mutex.Unlock()}return instance
}
4.sysc.Once
式
sysc.Once
是go標準庫提供的使函數只執行一次的實現,通常應用于單例模式,如初始化配置、保持數據庫連接等。其作用與init()
函數類似,但有區別。init()
函數會在其所在的包首次被加載時執行,如果被加載的包不立即被使用,那么既浪費了內存空間,又延長了程序加載時間。
sysc.Once
可以在代碼的任意位置被初始化和調用,在并發場景中是并發安全的,使用sysc.Once
對象的Do()方法創建實例,可以確保創建對象的方法只被執行一次
package typesofSigtonimport ("fmt""sync"
)
var once sync.Once
func GetIntance() *singleton{once.Do(func() {instance=new(singleton)fmt.Println("創建單個實例")})return instance
}
4)實踐案例
excample.go
package excampleimport ("fmt""sync"
)var lock = &sync.Mutex{}type singleton struct {
}var instance *singleton// 獲取實例對象
func GetInstance() *singleton {if instance == nil {lock.Lock()defer lock.Unlock()if instance == nil {fmt.Println("創建單個實例")instance = new(singleton)} else {fmt.Println("已創建單個實例")}} else {fmt.Println("已創建單個實例")}return instance
}
main.go
package mainimport ("Signton/excample""fmt"
)func main() {for i := 0; i < 3; i++ {go excample.GetInstance()}fmt.Scanln()
}//運行結果為
//創建單個實例
//已創建單個實例
//已創建單個實例
5)優缺點分析
優點:
- 單例模式可以擴展為工廠模式。
- 由于系統的內存中只存在一個對象,因此對于需要頻繁創建和銷毀對象的系統,使用單例模式可以提升系統的性能
缺點:
- 由于單例模式不是抽象的,因此其擴展性較低
- 濫用單例模式會產生一些負面問題。例如,為了節省資源,如果使用單例模式設計數據連接池對象,則可能會導致共享連接池對象過多且沒有被釋放的場景,從而出現連接池溢出的問題。此外,如果實例化的對象長時間不被使用,那么他可能會被操作系統認為是垃圾對象而回收,從而導致對象缺失。