1. 程式人生 > >寫一個單例的類

寫一個單例的類

就是寫一個例項化一次的類
即把構造私有化,外部無法例項化他。通過呼叫他的靜態方法,判斷是否例項化了,未例項化則例項化並返回,已例項化則返回已例項化的。

一:

/**
 * 基於雙重檢查鎖定的單例模式
 * @author zongzhimin
 *
 */
public class SingleDog4{

    /**
     * 在錯誤示範2的基礎上給instance加 volatile進行修飾
     * volatile可以保證instance的可見性禁止上個錯誤示例的那種重排序
     */
    private static volatile SingleDog4  instance    = null;

    private SingleDog4(){
    }

    public static SingleDog4 getInstance(){//雙重檢查防止多執行緒下出問題
        if (null == instance){// 1
            synchronized (SingleDog4.class){
                if(null == instance) {
                    instance = new SingleDog4();//2
                }

            }
        }
        return instance;
    }

    public void say(){
        System.out.println("Single all the way");
    }
}

二:

/**
 * 基於靜態內部類的單列模式
 * @author zongzhimin
 *
 */
public class SingleDog6{

    private SingleDog6(){
    }

    private static class InstanceHolder{
        final static SingleDog6 instance = new SingleDog6();
    }
    public static SingleDog6 getInstance(){
        return InstanceHolder.instance;
    }

    public void say(){
        System.out.println("Single all the way");
    }
}

效能不好:

/**
 * 這個效能不好
 * @author zongzhimin
 *
 */
public class SingleDog{

    private static SingleDog    instance    = null;

    private SingleDog(){
    }

    public static SingleDog getInstance(){//這裡每次獲取例項都要先獲取鎖,效能不好
        synchronized (SingleDog.class){
            if (null == instance){
                instance = new SingleDog();
            }
            return instance;
        }
    }

    public void say(){
        System.out.println("Single all the way");
    }
}

錯誤示範1:

/**
 * 錯誤示範1
 * @author zongzhimin
 *
 */
public class SingleDog2{

    private static SingleDog2   instance    = null;

    private SingleDog2(){
    }
    /**
     * 這裡做了改進將靜態快放在裡面但是這是錯誤的!!!
     * 多執行緒下A執行緒到1, B執行緒到2 -->(A判斷instance==null、正好B執行緒執行完2例項化一次)-->(這時A執行緒會進入靜態快再例項化一次。單例失敗)
     *      
     * @return
     */
    public static SingleDog2 getInstance(){
        if (null == instance){// 1
            synchronized (SingleDog2.class){
                instance = new SingleDog2();//2
            }
        }
        return instance;
    }

    public void say(){
        System.out.println("Single all the way");
    }
}

錯誤示範2:

/**
 * 錯誤示範2
 * @author zongzhimin
 *
 */
public class SingleDog3{

    private static SingleDog3   instance    = null;

    private SingleDog3(){
    }
    /**
     * 這裡在錯誤示範的基礎上做了改進增加一次進入靜態快的判斷!!!在塊裡再判斷一次,避免錯誤示範2裡面的再次例項化
     * 但這依然是不正確的:
     * 對於2操作: 可以分為  一:分配SingleDog3物件所需空間  二:初始化SingleDog3物件 三:將物件引用寫入instance物件
     * 由於重排序在臨界區(靜態快內的操作可以重排序)所以2操作可能是:一、三、二。
     * 因此:
     *      執行緒A進入靜態快且進行一、三、二的 三這一步(還未走二例項化SingleDog3但是已先給instance變數賦地址)
     *  而另一執行緒B進入1,發現instance不為null,然後return instance,此時執行緒A還未走完er,即SingleDog3還未例項化,程式出錯
     *      
     * @return
     */
    public static SingleDog3 getInstance(){
        if (null == instance){// 1
            synchronized (SingleDog3.class){
                if(null == instance) {
                    instance = new SingleDog3();//2
                }

            }
        }
        return instance;
    }

    public void say(){
        System.out.println("Single all the way");
    }
}