天天看點

設計模式(1) —— 單例模式

Singleton模式主要作用是保證在Java應用程式中,一個類Class隻有一個執行個體存在。

1.“保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。”就是static的getInstance方法,因為普通對象是通過new執行個體來通路,單例對象沒法new,自能通過static方法來通路了。

2.用途:如果不使用機制對視窗對象進行唯一化,将彈出多個視窗,如果這些視窗顯示的内容完全一緻,則是重複對象,浪費記憶體資源;如果這些視窗顯示的内容不一緻,則意味着在某一瞬間系統有多個狀态,與實際不符,也會給使用者帶來誤解,不知道哪一個才是真實的狀态。是以有時確定系統中某個對象的唯一性即一個類隻能有一個執行個體非常重要。

3.展示臨時狀态,瞬間狀态。唯一性。

4.單例模式的要點有三個;一是某個類隻能有一個執行個體;二是它必須自行建立這個執行個體;三是它必須自行向整個系統提供這個執行個體。

單例模式的優缺點

1、時間和空間

比較上面兩種寫法:懶漢式是典型的時間換空間,也就是每次擷取執行個體都會進行判斷,看是否需要建立執行個體,浪費判斷的時間。當然,如果一直沒有人使用的話,那就不會建立執行個體,則節約記憶體空間。

餓漢式是典型的空間換時間,當類裝載的時候就會建立類執行個體,不管你用不用,先建立出來,然後每次調用的時候,就不需要再判斷了,節省了運作時間。

2、線程安全

(1)從線程安全性上講,不加同步的懶漢式是線程不安全的,比如,有兩個線程,一個是線程A,一個是線程B,它們同時調用getInstance方法,那就可能導緻并發問題。

(2)餓漢式是線程安全的,因為虛拟機保證隻會裝載一次,在裝載類的時候是不會發生并發的。

(3)如何實作懶漢式的線程安全呢?

當然懶漢式也是可以實作線程安全的,隻要加上synchronized即可,如下:public static synchronized Singleton getInstance(){} 

但是這樣一來,會降低整個通路的速度,而且每次都要判斷。那麼有沒有更好的方式來實作呢?

(4)雙重檢查加鎖

可以使用"雙重檢查加鎖"的方式來實作,就可以既實作線程安全,又能夠使性能不受到很大的影響。

所謂雙重檢查加鎖機制,指的是:并不是每次進入getInstance方法都需要同步,而是先不同步,進入方法過後,先檢查執行個體是否存在,如果不存 在才進入下面的同步塊,這是第一重檢查。進入同步塊過後,再次檢查執行個體是否存在,如果不存在,就在同步的情況下建立一個執行個體,這是第二重檢查。這樣一來, 就隻需要同步一次了,進而減少了多次在同步情況下進行判斷所浪費的時間。

public class Singleton {  
        /**  
         * 對儲存執行個體的變量添加volatile的修飾  
         */  
        private volatile static Singleton instance = null;  
        private Singleton(){  
        }  
        public static  Singleton getInstance(){  
            //先檢查執行個體是否存在,如果不存在才進入下面的同步塊  
            if(instance == null){  
                //同步塊,線程安全地建立執行個體  
                synchronized(Singleton.class){  
                    //再次檢查執行個體是否存在,如果不存在才真正地建立執行個體  
                    if(instance == null){  
                        instance = new Singleton();  
                    }  
                }  
            }  
            return instance;  
        }  
    }      

這種實作方式可以實作既線程安全地建立執行個體,而又不會對性能造成太大的影響。它隻是在第一次建立執行個體的時候同步,以後就不需要同步了,進而加快了運作速度。

繼續閱讀