Modèle de conception - une brève introduction au modèle singleton

Principe du mode Singleton

Qu'est-ce qu'un objet singleton?

Pour certains objets, nous n'en avons besoin que d'un tel que le pool de threads, la source de données de cache, le périphérique matériel, etc. S'il y a plusieurs instances, cela entraînera des conflits et des résultats incohérents.Après tout, vous avez et moi, mais ce que vous avez peut ne pas être exactement le même que ce que j'ai. L'utilisation du modèle singleton peut garantir qu'il existe au plus une instance d'une classe et fournir un point d'accès global.

public class Test {
    public class ABC {
        public ABC() {
        }

//        private ABC() {  //为这个内部类申明私有的构造方法,外部则无法通过new初始化,只能类自己初始化
//        }
//        ABC n1 = new ABC();
    }

    public class CDB {
        public CDB() {
            ABC n1, n2;
            n1 = new ABC();
            n2 = new ABC();
            System.out.println("CBD: " + (n1 == n2));    //false
        }
    }

    public static void main(String[] args) {
        ABC n1, n2;
        n1 = new Test().new ABC();
        n2 = new Test().new ABC();
        System.out.println("main: " + (n1 == n2));   //false
        new Test().new CDB();
    }
}

Alors, y a-t-il un moyen de rendre le nouvel objet le même à chaque fois? Regardez le diagramme de classe de modèle singleton ci-dessous, vous pouvez trouver quelques idées!

Singleton (singleton)
static uniqueInstance (déclaration d'objet unique statique)
private singleton () (méthode d'instanciation privée)
static getInstance () (point d'accès global)

Combat de codage

Après avoir compris le contenu ci-dessus, écrivons un simple code en mode singleton, le code est le suivant:

public class Singleton {
    private static Singleton uniqeInstance = null;    //静态变量

    private Singleton() {    // 私有的构造方法,外部无法使用
    }

    public static Singleton getInstance() {
        if (uniqeInstance == null) {
            uniqeInstance = new Singleton();
        }
        return uniqeInstance;
    }
}

Puisque les variables statiques n'appartiennent à aucun objet d'instance, elles appartiennent à des classes, il n'y aura donc qu'une seule copie en mémoire. Pendant le processus de chargement de la classe, JVM alloue de l'espace mémoire pour les variables statiques une fois.

Imaginons ce scénario: une usine alimentaire, il n'y a qu'une seule usine, puis il n'y a qu'un seul pot dans l'usine. Après avoir fabriqué un lot d'aliments, nous pouvons fabriquer le lot suivant. À ce stade, notre objet usine alimentaire est un singleton. Voici l'implémentation de la simulation. Le code, l'implémentation singleton du code est différent de l'implémentation simple ci-dessus, il a été optimisé, et j'expliquerai pourquoi il est optimisé plus tard

public class ChocolateFactory {
    private boolean empty;   // 空锅
    private boolean boiled;  // 加热
    public volatile static ChocolateFactory uniqueInstance = null;

    private ChocolateFactory() {
        empty = true;    // 锅是空的
        boiled = false;  // 还没加热
    }

    public static ChocolateFactory getInstance() {
        if (uniqueInstance == null) {
            synchronized (ChocolateFactory.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new ChocolateFactory();
                }
            }
        }
        return uniqueInstance;
    }
    // 第一步装填
    public void fill() {
        if (empty) {  // 锅是空的
            // 添加原料巧克力动作
            empty = false;  // 锅装满了,不是空的
            boiled = false;  // 还没加热
        }
    }
    // 第三步倒出
    public void drain() {
        if ((!empty) && boiled) {  // 锅不是空的,已经加热
            // 排出巧克力动作
            empty = true;   //出锅,锅空了
        }
    }
    // 第二步加热
    public void boil() {
        if ((!empty) && (!boiled)) {  // 锅不是空的,没加热
            // 煮沸
            boiled = true;  // 已经加热
        }
    }
}

Problèmes et optimisation du mode singleton

problème

Dans le cas du multithreading, il y aura le concept de tranches de temps et de concurrence CPU. C'est exactement ce qui se passe lorsque des problèmes peuvent survenir en mode singleton? Prenons l'exemple du code d'usine de transformation des aliments

public synchronized static ChocolateFactory getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new ChocolateFactory();
       }
       return uniqueInstance;
   }

Dans le cas du multithreading, deux objets seront instanciés

Solution optimisée

Méthode getInstance synchronisée (synchronisée)

Le thread 1 est exécuté if (uniqueInstance == null)et le droit d'exécution est volé par le thread 2. À ce stade, le thread 1 n'a pas de nouvel objet; Thread 2 est également venu if (uniqueInstance == null), et a trouvé qu'il n'y avait pas d'instance d'objet et prévoyait d'instancier l'objet; enfin, le thread 1 et le thread 2 s'exécuteront uniqueInstance = new ChocolateFactory();à ce moment. Le modificateur synchronized est ajouté avant la méthode getInstance () . Cependant, cette méthode est plus gourmande en performances lorsque les appels multithreads sont fréquents.

Créer une instance "avec empressement"

public class ChocolateFactory {
    public static ChocolateFactory uniqueInstance = new ChocolateFactory();  //“急切”创建实例
    public static ChocolateFactory getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new ChocolateFactory();
       }
       return uniqueInstance;
   }
}

public static ChocolateFactory uniqueInstance = new ChocolateFactory();L'objet d'instance est chargé et initialisé une fois au démarrage de l'application. À ce stade, les appels multithreads n'auront toujours qu'une seule instance, car if (uniqueInstance == null)le résultat est toujours faux; mais si la paire d'objets singleton n'est pas utilisée dans l'application, utilisez ceci La méthode consomme de l'espace mémoire

Vérifier et verrouiller (meilleur)

public class ChocolateFactory {
    //用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。
    public volatile static ChocolateFactory uniqueInstance = null;   
    public static ChocolateFactory getInstance() {
        if (uniqueInstance == null) {
            synchronized (ChocolateFactory.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new ChocolateFactory();
                }
            }
        }
        return uniqueInstance;
    }
}

Tout public volatile static ChocolateFactory uniqueInstance = null;d'abord, l'objet n'est pas initialisé au démarrage de l'application, ce qui économise de la mémoire; d'autre part , le bloc de code modifié par synchronized est à nouveau if (uniqueInstance == null) {}jugé, et ce n'est que lorsque les conditions sont remplies qu'il entrera dans la méthode de synchronisation, réduisant la consommation de performances.

Je suppose que tu aimes

Origine blog.csdn.net/doubututou/article/details/109210319
conseillé
Classement