シングルトンを作成する方法、あなたはいくつかのフォームを知っていますか?

「シングルトンの作り方、フォームの数知ってる?」インタビュアー
幽霊のような笑顔を見せてくれた幸い、読んだ「本」を思い出した!


コードでのシングルトンの作成に関して、Zihan氏は6つの一般的な方法を要約しました。
ここに写真の説明を挿入

空腹の中国人

オブジェクトを直接作成します。スレッドの安全性の問題はありません。
重要な要素:

  • クラスは1つのインスタンスしか持つことができません-コンストラクターはプライベート化されています。
  • このインスタンスは自分で作成する必要があります-クラスの静的変数。
  • このインスタンスをシステム全体に自分で提供する必要があります—(1)直接公開;(2)静的変数のメソッドを取得します。

空腹の中国スタイルを直接インスタンス化します(簡潔で直感的)

public class Singleton1 {
    
    
	// 使用public直接暴露
    public static final Singleton1 INSTANCE = new Singleton1();
    private Singleton1() {
    
    
    }
    // 使用public方法直接暴露
    public static Singleton1 getInstance(){
    
    
        return INSTANCE;
    }
}

列挙(最も簡潔)

/**
 * 推荐
 */
public enum SingletonEnum {
    
    
    INSTANCE
}

静的コードブロック空腹の中国スタイル(複雑なインスタンス化に適しています)

/**
 * 基于外部配置的单例
 */
public class SingletonStaticBlock {
    
    
    public static final SingletonStaticBlock INSTANCE;
    private String info;
    static {
    
    
        Properties por = new Properties();
        try {
    
    
            por.load(SingletonStaticBlock.class.getClassLoader().getResourceAsStream("single.properties"));
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        INSTANCE = new SingletonStaticBlock(por.getProperty("hello"));
    }

    private SingletonStaticBlock(String info) {
    
    
        this.info = info;
    }

    public String getInfo() {
    
    
        return info;
    }

    public void setInfo(String info) {
    
    
        this.info = info;
    }
}

リソースの下にファイルを追加しますsingle.properties

hello = Mr.zihan

次にテストします〜

    @Test
    public void testSingleton(){
    
    
//        Singleton singleton = new Singleton();//无法new
//        Singleton1 singleton1 = new Singleton1();//无法new
        System.out.println(SingletonEnum.INSTANCE);
        System.out.println(Singleton1.INSTANCE);
        System.out.println(SingletonStaticBlock.INSTANCE.getInfo());
    }

試験結果:

INSTANCE
com.dwlijx.pattern.creation.single.Singleton1@eec5a4a
Mr.zihan

怠惰な人間

オブジェクトの作成を遅らせます。
キーポイント:

  • (1)コンストラクターの民営化
  • (2)静的変数は唯一のインスタンスを保存します。
  • (3)このインスタンスのオブジェクトを取得するための静的メソッドを提供します

スレッドは安全ではありません(シングルスレッドに適しています)

public class SingletonLazy {
    
    
	// 需要时再实例化
    private static SingletonLazy INSTANCE;
    private SingletonLazy() {
    
    
    }

    public static SingletonLazy getINSTANCE(){
    
    
        if (null == INSTANCE){
    
    
            INSTANCE = new SingletonLazy();
        }
        return INSTANCE;
    }
}

短所:スレッドは安全ではなく、シングルスレッドのシナリオに適しています。
テストする:さらに
数回試行する必要がある場合があります。

/**
     * 懒汉模式
     * 用两个线程getInstance,比对一下实例的hashCode
     */
    @Test
    public void securityTest() throws ExecutionException, InterruptedException {
    
    
        Callable<SingletonLazy> callableTask = new Callable<SingletonLazy>() {
    
    
            @Override
            public SingletonLazy call() throws Exception {
    
    
                return SingletonLazy.getINSTANCE();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<SingletonLazy> f1 = es.submit(callableTask);
        Future<SingletonLazy> f2 = es.submit(callableTask);

        System.out.println(f1.get().hashCode());
        System.out.println(f2.get().hashCode());
        es.shutdown();
    }
1316864772
1685232414

スレッドの安全性を確保するためのクラスロック(マルチスレッドに適用可能)

前の例に基づいて、マルチスレッドの安全性を制御する手段が追加されています。

public class SingletonLazySafe {
    
    
    private static SingletonLazySafe instance;
	//构造方法私有
    private SingletonLazySafe() {
    
    
    }

    public static SingletonLazySafe getInstance(){
    
    
        // 双重校验锁提升效率
        if (null == instance){
    
    
            synchronized (SingletonLazySafe.class){
    
    
                if (null == instance){
    
    
                    instance = new SingletonLazySafe();
                }
            }
        }
        return instance;
    }
}

テストがあります

1316864772
1316864772

だから問題は、hashCodeが初期化されるたびに同じ値になる理由を知っていますか?たとえば1316864772

静的内部クラス形式(マルチスレッドに適しています)

(1)コンストラクターのプライベート化
(2)内部クラスの静的変数は唯一のインスタンスを保存します;それは
使用され内部类的加载特性ます:内部クラスは外部クラスのロードと初期化で自動的に初期化されませんが、別々にロードされて初期化されます。

public class InnerClassLazySingleton {
    
    

    private InnerClassLazySingleton() {
    
    
    }

    public static class Inner{
    
    
        private static InnerClassLazySingleton INSTANCE = new InnerClassLazySingleton();
    }

    public static InnerClassLazySingleton getInstance(){
    
    
        return Inner.INSTANCE;
    }
}

テストがあります

/**
     * 懒汉模式-解决线程安全问题
     * 用两个线程getInstance,比对一下实例的hashCode
     */
    @Test
    public void innerClassSingletonSafeTest() throws ExecutionException, InterruptedException {
    
    
        Callable<InnerClassLazySingleton> callableTask = new Callable<InnerClassLazySingleton>() {
    
    
            @Override
            public InnerClassLazySingleton call() throws Exception {
    
    
                return InnerClassLazySingleton.getInstance();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<InnerClassLazySingleton> f1 = es.submit(callableTask);
        Future<InnerClassLazySingleton> f2 = es.submit(callableTask);

        System.out.println(f1.get().hashCode());
        System.out.println(f2.get().hashCode());
        es.shutdown();
    }

試験結果:

1285044316
1285044316

ここに写真の説明を挿入

よろしくお願いします。ゲストオフィサー、いいね、メッセージを残して残してください〜または質問を残してください。一緒に話し合います〜

ここに写真の説明を挿入

おすすめ

転載: blog.csdn.net/l714417743/article/details/108697935