Java設計モード-単例モード(Singleton)の【原理と実現】

4025 ワード

引用:
単例モードはソフトウェア開発で最も一般的な設計モードの一つであり、その名の通り、システム全体でインスタンスオブジェクトが1つしか取得され、使用できない.
そのポイントは3つあります.
  • クラスには1つのインスタンスしかありません.プライベート構造関数
  • です.
  • このインスタンスは、クラスによって独自に作成されます.クラスの静的変数は、この一意のインスタンス
  • を保存します.
  • は、この例を自分でシステムに提供しなければならない.1.直接暴露2.静的方法getを
  • に提供する.
    (餓漢式でも怠け者式でも以上の3点を表しています)
    2つの一般的な形式
  • 餓漢:いずれにしてもインスタンスオブジェクトが直接作成されます(スレッドセキュリティの問題なし)
  • 怠け者:スレッドセキュリティの問題に直面するインスタンスオブジェクトの作成を遅延する
  • 一、餓漢式(三つの方式)
          餓漢式には,直接インスタンス化,列挙タイプ,静的コードブロックの3つの方法がある.餓漢式はスレッドセキュリティの問題に関与せず、クラスをロードするときにオブジェクトを初期化します.
    第1版:直接に餓漢式を実例化する
    public class Singleton1 {
    	public static final Singleton1 INSTANCE = new Singleton1();  
    	private Singleton1(){  //      
    		
    	}
    }

    Test: 
    public class Singleton1Test {
    	public static void main(String[] args) {
    		Singleton1 singleton1 = Singleton1.INSTANCE;
    		System.out.println(singleton1);
    	}
    
    }
    

    第2版:列挙タイプ
    列挙タイプは、このタイプのオブジェクトが有限であることを示します.まず1つにすることができます.
    public enum Singleton2 {
    	INSTANCE;
    }
    

    Test方式は前と同じです.
    public class Singleton2Test {
    	public static void main(String[] args) {
    		Singleton2 Singleton2 = Singleton2.INSTANCE;
    		System.out.println(Singleton2);
    
    	}
    }

    第3版:静的コードブロック
           この方法は,第1版の静的オブジェクトインスタンス化プロセスを静的コードブロックに書くことであり,明らかに複雑に見えるが,第1種より簡潔明瞭ではない.その適用シーンは、コンストラクション関数がパラメータ付きである場合、config.propertiesにパラメータが書かれています.
    次のようになります.
    name=JakeLin

    このような構成は、静的コードブロックにロードできます. 
    public class Singleton3 {
    	public static final Singleton3 INSTANCE ;
    	private String name;
    	static{
    		Properties pro = new Properties();
    		try {
    			pro.load(Singleton3.class.getClassLoader().getResourceAsStream("config.properties"));
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		INSTANCE = new Singleton3(pro.getProperty("name"));
    	}
    	private Singleton3(String info){
    		this.name = name;
    	}
    	public String toString() {
    		return "Singleton3 [name=" + name + "]";
    	}
    	
    }

    Test:
    public class Singleton3Tset {
    	public static void main(String[] args) {
    		Singleton3  singleton3 = Singleton3.INSTANCE;
    		System.out.println(singleton3);
    	}
    }
    

     
     二、怠け者式
           怠け者式は餓漢が多すぎて、いつクラスをロードしてもnewオブジェクトが1つあると思っていますが、このクラスの1つのメソッドを呼び出すだけで、このオブジェクトを作成したくない場合があります.そのため、怠け者はクラスをロードするときにnewインスタンスオブジェクトをロードするのではなく、このインスタンスオブジェクトを取得するための静的なメソッドを提供し、オブジェクトを作成するには、このメソッドを呼び出します.
    public class Singleton4 {
    	static Singleton4 instance;  //        
    	private Singleton4(){  //      
    		
    	}
    	public static Singleton4 getInstance(){
    		if(instance == null){  //    
    			instance = new Singleton4();
    		}
    		return instance;
    	}
    }
    

           単一スレッドの場合、この方法は問題ありませんが、マルチスレッドの場合、スレッドセキュリティの問題が発生します.
           スレッド1が入ってくると、インスタンスが空であることがわかります.では、インスタンスを作成します.このとき、スレッド2が入ってきます.スレッド1はまだ作成されていません.スレッド2はインスタンスも空であることを発見します.では、インスタンスも作成されます.結果として、2つのスレッドが2つの異なるインスタンスを作成し、1つの例の原則に反します.これは怠け者のスレッドの安全問題です.
          どうやって解決しますか?ロックをかける方法で解決することは容易です.
    public class Singleton4 {
    	static Singleton4 instance;
    	private Singleton4(){
    		
    	}
    	public static Singleton4 getInstance(){
    		if (instance == null) {  //     ,           ,           
    			//       
    			synchronized (Singleton4.class) {  //   
    				if(instance == null){
    					instance = new Singleton4();
    				}
    			}
    		}
    		return instance;
    	}
    }

           このように書くのは少し複雑に見えますが、 また、内部クラスがロードおよび初期化されたときにオブジェクトを作成し、怠け者のスレッドセキュリティの問題を解決する別の方法もあります.
    public class Singleton5 {
    	private Singleton5(){
    		
    	}
    	public static class inner{  //      
    		private static Singleton5 INSTANCE;
    	}
    	public static Singleton5 getInstance(){  //                 
    		return inner.INSTANCE;
    	}
    }
    

          静的内部クラスは、外部クラスがロードおよび初期化されるにつれて自動的にロードおよび初期化されるのではなく、単独でロードおよび初期化されるからです.内部クラスのロードと初期化時にオブジェクトが作成されるため、スレッドは安全です.
     
    まとめ:
    以上が餓漢式と怠け者式の2つの単例モデルであり,餓漢式はスレッドの安全問題を考慮する必要はなく,怠け者式は必要である.餓漢式はクラスをロードするときにインスタンスを作成し、怠け者式はメソッドを呼び出すときにインスタンスを作成します.