1. 程式人生 > >Java基礎:多執行緒下的單例模式

Java基礎:多執行緒下的單例模式

       單例物件(Singleton)是一種常用的設計模式。在Java應用中,單例物件能保證在一個JVM中,該物件只有一個例項存在。但在多執行緒環境下,就可能會產生問題,並不一定能保證只有一個例項。具體問題描述和解決方法如下。

/*
 * 多執行緒下的單例方式一:
 * 餓漢式,提前載入,執行緒安全
 */

public class SingleDemo {
    private static final SingleDemo s=new SingleDemo();
    private SingleDemo(){}

    public static SingleDemo getInstance
(){ return s; } }
/*
 * 多執行緒下的單例方式二:
 * 懶漢式,延時載入,執行緒不安全
 */
public class SingleDemo {       
    private static SingleDemo s=null;
    private SingleDemo(){}

    public static SingleDemo getInstance(){
        if(s==null)
            s=new SingleDemo();
        return s;
    }
}

       執行緒不安全分析:當執行緒1判斷s==null時,發現為null,準備建立物件;此時,執行權切換到執行緒2,執行緒2判斷s==null,發現也為null,也會建立新物件,這樣在一個JVM會有多個單例型別的物件例項。解決執行緒不安全的方法如下:

public class SingleDemo {
    private static SingleDemo s=null;
    private SingleDemo(){}

    //使用同步函式解決執行緒安全問題,使用的鎖物件是SingleDemo.class
    //問題:所有執行緒都需要判斷鎖,浪費資源
    public static synchronized SingleDemo getInstance(){
        if(s==null)
            s=new SingleDemo();
        return s;
    }
}
public
class SingleDemo { private static SingleDemo s=null; private SingleDemo(){} //使用同步程式碼塊解決執行緒安全問題,使用的鎖物件是SingleDemo.class //問題:所有執行緒都需要判斷鎖,浪費資源 public static SingleDemo getInstance(){ synchronized(SingleDemo.class){ if(s==null) s=new SingleDemo(); } return s; } }

       使用同步函式或上述同步程式碼塊解決執行緒安全問題帶來的一個弊端就是,每個執行緒都需要判斷同步鎖,會浪費資源,降低效率,因此可以多加一次判斷來解決資源浪費問題。

public class SingleDemo {
    private static SingleDemo s=null;
    private SingleDemo(){}

    //解決執行緒同步效率問題
    public static SingleDemo getInstance(){
        if(s==null){//多加一步判斷,就可以使得不是所有執行緒都判斷鎖,解決效率問題
            synchronized(SingleDemo.class){
                if(s==null)
                    s=new SingleDemo();
            }
        }
        return s;
    }
}

       此外,還有另外一種不使用同步鎖的解決辦法,即使用私有的靜態內部類,當不呼叫getInstance()方法時,就不會呼叫這個內部類,就不會產生例項。具體程式碼如下:

public class SingleDemo {
    private SingleDemo(){} 

    //私有的靜態內部類,當不呼叫getInstance()方法時,就不會呼叫這個內部類,就不會產生例項
    private static class Inner{   //私有的靜態內部類    
        static SingleDemo s = new SingleDemo();  
    }  

    public static SingleDemo getInstance(){  
        return Inner.s;  
    }  
}