1. 程式人生 > >關鍵字static與單例模式的一點理解

關鍵字static與單例模式的一點理解

static是java語言中的一個關鍵字,表示一個靜態修飾符,修飾符比較容易理解,靜態修飾符又有什麼特點呢,首先程式中的任何變數或者程式碼都是在編譯時,由系統自動分配記憶體來儲存的,而靜態的特點就是指,在編譯後所分配的記憶體會一直存在,直到程式退出是才會釋放這個空間。計算機語言是這樣描述的,那程式語言又應該怎樣去解釋這個東西呢,以java語言為例:java語言中所有的東西都可以理解為物件(java是一門面向物件的程式語言),物件就可以理解為我們常說的類,類中通常都會有一些成員變數或者成員方法,在不考慮訪問許可權的情況下,需要先例項化物件(通俗一點就是先new 物件),然後通過物件的引用,就可以訪問這些成員變數或者方法。然而有一種情況是例外的——用static修飾符修飾的變數或者方法。因為一個變數或者有方法,用static修飾時,在類載入的是時候,就已經分配了記憶體空間,且在程式就是前一直存在,所有jvm虛擬機器不需要穿件類的實力物件就可以找到該記憶體區域,呼叫相應的方法或者屬性。所以,再運用靜態的方法時也就有了一些限制。
· 它們僅能呼叫其他的static 方法,
· 它們只能訪問static資料。
· 它們不能以任何方式引用this 或super。
原因很簡單,類載入就產生的東西也只能呼叫類載入的時候就產生了的東西。
然後再來談談與static息息相關的東西——單例模式。
簡單來說,單例模式可以理解為:在任何時刻,確保一個類只有一個例項,並提供一個全域性的訪問點。首先要知道物件是通過什麼樣的途徑建立的,然後才能想辦法確保只產生一個類例項。建立類物件,既——呼叫類的無參構造方法,建立類物件(這個說法可能並不全面),也就是常說的new 物件();因為要建立一個任何情況都只有一個類例項,所以我們就要先控制這個無參構造方法的訪問許可權為私有的,只有在類自己的內部參能呼叫這個構造方法。然而,類不出建立,又如何呼叫無參的構造方法來建立物件呢?那麼就是憑藉單例模式的核心:static。寫一個靜態方法(不需要建立物件,再類載入之後就可以呼叫),在這個靜態方法內部,呼叫構造方法,來建立物件。方法返回值為這個類物件。一個簡單的單例模式就完成了

public class Singleton {

    private Singleton(){

    }
    public static Singleton getInstance(){
        return new Singleton();
    }
}

單例模式確實是實現了,私有的構造方法,公有的靜態方法返回類例項,然而在有些時候會出現一些問題:併發。電腦由cup執行程式,而java是多執行緒的語言。所以當兩個執行緒同時呼叫靜態方法去得到例項的時候,還是有極小的可能出現問題,得到兩個類例項。所以,這個單例模式需要一點點修改。

public class
Singleton { private static Singleton singleton =new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return singleton; } }

這樣寫,在類載入的時候就產生了類例項,所以就保證了執行緒安全,但是這樣還有一個缺點,就是失去了延遲載入的特性,如果程式中有1w個單例,不管用沒用到,在類載入的時候就全部產生例項,會造成不必要的冗餘和負擔,這樣做並不好。所以,需要用到另外一個方法——同步,在用同步的時候,需要考慮另外一個問題,就是效率的問題,因為在使用synchronized的時候,一個執行緒在執行synchronized中的程式碼的時候如果別的執行緒也要執行其中的程式碼就要等到之前的執行緒執行完之後在才能夠進入。

public class Singleton {
    private static Singleton singleton ;
    private Singleton(){

    }
    public static Singleton getInstance(){
        if(singleton==null){
            synchronized (Singleton.class) {
                if(singleton==null){
                    singleton=new Singleton();
                }
            }
        }
            return singleton;
    }
}

首先判斷,物件是否已經建立,如果沒有建立,則進入同步程式碼中,進入之後再判斷是否已經建立,排除第一次建立時就發生併發的問題,如果已經建立則結束同步程式碼,如果為建立,則建立物件。其中同步鎖用類的位元組碼也就是Singleton.class。這樣實現單例模式的時候,只有第一次建立類例項的時候進入了同步鎖中。極大的避免了同步所帶來的等待問題。鎖內和鎖外兩次判斷也確保了類例項的唯一性。