1. 全局變量的缺點:數據庫
必須在程序一開始就建立好對象,若是程序在此次的執行過程當中又一直沒用到它,就很是耗費資源。緩存
2. 經典的單例模式實現:安全
public class Singleton { //用一個靜態變量來記錄Singleton類的惟一實例 private static Singleton uniqueInstance; private Singleton() {} //注意這個方法也是靜態的 public static Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }
單例常被用來管理共享的資源,例如數據庫鏈接、線程池、緩存、註冊表。多線程
單例模式確保一個類只有一個實例,並提供一個全局訪問點。性能
這個模式的問題:在多線程時,並不能保證這個類只被實例化一次。優化
3. 處理多線程:spa
經過增長synchronized關鍵字到getInstance()方法中,迫使每一個線程在進入方法以前,要先等別的線程離開該方法。也就是說,不會有兩個線程能夠同時進入這個方法。線程
這種方法存在的問題:只有第一次執行此方法時,才真正須要同步。換句話說,一旦設置好uniqueInstance變量,就再也不須要同步這個方法了。以後每次調用這個方法,同步都是一種浪費。code
4.改善多線程對象
4.1 若是getInstance()的性能對應用程序不是很關鍵,就不用優化了
4.2 使用急切建立實例,而不用延遲實例化的作法
public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return uniqueInstance; } }
標紅的語句在靜態初始化器(static initializer)中建立單例,這保證了線程安全。
利用這個作法,JVM在加載這個類時立刻建立此惟一的單件實例。JVM保證任何線程訪問uniqueInstance靜態變量以前,必定先建立些實例。
4.3 用「雙重檢查加鎖」,在getInstance()中減小使用同步
首先檢查實例是否已經建立,若是還沒有建立,才進行同步。這樣一來,只有第一次會同步,這正是咱們想要的。
public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if(uniqueInstance == null) {//(1)
//只有第一次才完全執行這裏的代碼 synchronized() { //再檢查一次 if(uniqueInstance == null) uniqueInstance = new Singleton(); } } return uniqueInstance; } }
在最開始若是有一、二、3個線程走到了(1)處,假設1進入了同步塊,二、3等待。1實例化後,2進入同步塊,發現uniqueInstance已經不爲空,跳出同步塊。接着3進入,又跳出同步塊。
volatile關鍵字確保:當uniqueInstance變量被初始化成Singleton實例時,多個線程正確地uniqueInstance變量。若是性能是你關心的重點,那麼這個作法能夠幫你大大地減小getInstance()的時間耗費。