一、為什麼要用單例模式
當一個類需要用來管理共享資源的時候,我們就隻需要一個對象,比方說:線程池、緩存、日志對象等等。如果說制造出了多個執行個體,就會導緻許多問題的産生,例如:程式異常,資源使用過量,結果不一緻等等。
舉個簡單的例子就是,當一個web應用中連接配接資料庫的Connection對象,如果每次通路都new一個出來,那麼當有一萬個甚至更多的通路在短時間内并發,這将導緻伺服器資源的大量開銷,因為這些對象不回被垃圾回收立刻收回。但如果伺服器對此隻執行個體化一次,每次Connection對象被使用後放回線程池,其他通路過來時在重新使用它,這便使得伺服器性能大大的提升了,這裡就要用單例模式去實作程式了。
二、金典單例模式實作
*注意:金典單例實作隻适用于單線程的情況,當有多個線程并發時,它們都要執行這段代碼,都執行到第6行,這時sl都為空,于是乎就會執行個體出多個對象了,這就違背了單例模式的思想了。
三、多線程場景下的單例模式
1.大家很容易想到在getInstance()方法上加上synchronized關鍵字就能解決線程并發時的問題了。
*注意:但是我們可以想象得到,真正需要同步的是在第一次調用時,之後就不再需要同步這個方法了。之後的每次調用,同步都會是一種累贅。程式執行的效率就會大大降低。
2.使用“急切”建立執行個體,而不用延遲延遲執行個體化的做法
JVM虛拟機在加載這個類時就會立馬建立此唯一的單例。
3.使用“雙重加鎖”,在getInstance()方法中減少使用同步
這樣就能延遲建立執行個體,并且是線程安全的。
四、總結
為了保證能在多線程場景下程式不會出錯,通常我們應該選擇後兩種實作方式中的一種。至于具體用哪種更好,這個可以更具具體的需求來定:
1.程式總是建立并使用單例時,選擇“急切”建立執行個體的實作吧。
2.如果不是1,就用“雙重加鎖”吧。
最後,在單線程的情況下,還是推薦使用金典。金典感覺總是挺好的。嘿嘿。