English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
L'article présente un exemple d'utilisation du modèle Singleton dans la programmation Android. Partageons-le pour que vous puissiez vous en inspirer, voici les détails :
Un, introduction
Le modèle Singleton est l'un des modèles les plus largement utilisés, et peut-être même le seul que de nombreux ingénieurs débutants sauront utiliser. Lors de l'application de ce modèle, la classe de l'objet Singleton doit garantir qu'il n'existe qu'une seule instance. Souvent, tout le système n'a besoin que d'un objet global, ce qui est favorable à la coordination du comportement global du système.
Deux, définition
Assurer qu'une seule instance d'une classe existe, et qu'elle s'auto-instancie pour fournir cette instance à tout le système.
Trois, scénarios d'utilisation
Scénario où il est assuré qu'un seul objet d'une certaine classe existe, évitant ainsi la création de multiples objets qui consomment trop de ressources, ou où un certain type d'objet ne devrait exister qu'une seule fois. Par exemple, créer un objet nécessitant beaucoup de ressources, comme accéder aux ressources IO et bases de données, il faut alors envisager d'utiliser le modèle Singleton.
Quatre, méthodes d'implémentation
1、Mode affamé
Exemple de code :
/** * Mode affamé */ public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
Avantages:Chargement différé (se charge seulement lorsque nécessaire)
Inconvénients:Non sécurisé en mode thread, il est facile de se rencontrer dans des situations asynchronisées dans un environnement multithreadé, par exemple, lors d'opérations de lecture/écriture fréquentes sur des objets de base de données.
2、Mode paresseux
Exemple de code :
/** * Mode paresseux */ public class Singleton { private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
Comparé au modèle de hamster affamé, la méthode getInstance() ajoute la clé synchronize, ce qui signifie que getInstance est une méthode synchronisée, et cela garantit l'unicité de l'objet singleton dans le cas de multiples threads. Cependant, en y réfléchissant plus profondément, vous pourriez découvrir un problème : même si instance a été initialisé (instance sera initialisé lors du premier appel), chaque appel à la méthode getInstance nécessite une synchronisation, ce qui entraîne une consommation de ressources inutiles, ce qui est le plus grand problème du modèle de hamster paresseux.
Avantages:Il résout le problème de sécurité des threads.
Inconvénients:Il est nécessaire de procéder à l'instanciation à temps lors du premier chargement, mais la réaction est un peu lente, et le problème le plus important est que chaque appel à getInstance nécessite une synchronisation, ce qui entraîne des coûts de synchronisation inutiles.
Complément:Les méthodes singleton utilisées dans le code source d'Android incluent InputMethodManager, AccessibilityManager, etc., qui utilisent ce modèle de singleton
3、Double Check Lock (DCL) double vérification verrouillage
Exemple de code :
/** * Le modèle de singleton avec vérification double (DCL) */ public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
Le point fort de ce programme se situe naturellement dans la méthode getInstance, où getInstance effectue deux vérifications de null sur instance : le premier niveau de jugement est principalement pour éviter des synchronisations inutiles, et le deuxième niveau de jugement est pour créer l'instance en cas de null.
Supposons que le thread A exécute la phrase instance = new Singleton(), cela semble être une ligne de code, mais en réalité, ce n'est pas une opération atomique. Cette phrase de code sera finalement compilée en plusieurs instructions assembleur, qui font essentiellement3une chose :
(1)alloue de la mémoire à l'instance Singleton;
(2)appelle le constructeur Singleton(), initialise les champs membres;
(3)pointe l'objet instance vers l'espace mémoire alloué (à ce moment-là, instance n'est plus null).
Cependant, en raison de l'ordre d'exécution désordonné permis par le compilateur java, ainsi que par JDK1.5l'ordre de réécriture de Cache, registre vers la mémoire principale du modèle mémoire JMM (Java Memory Model, c'est-à-dire le modèle mémoire Java) précédent, l'ordre des deuxièmes et troisièmes phrases n'est pas garanti. Autrement dit, l'ordre d'exécution peut être1-2-3peut-être aussi1-3-2Si c'est le cas, et que dans3Terminé、2Avant l'exécution, il est passé à la ligne B, à ce moment-là, instance a déjà été exécuté au sein du thread A, instance est déjà non vide, tous, thread B prend directement instance, et il y aura une erreur lors de son utilisation, c'est le problème d'échec du DCL, et cette erreur difficile à suivre et à reproduire pourrait rester cachée pendant longtemps.
Dans JDK1.5Après cela, l'officiel SUN a noté ce problème, ajusté le JVM, et spécifié la clé volatile, donc si JDK est1.5ou versions ultérieures, il suffit de modifier la définition de instance en private volatile static Singleton instance pour garantir que l'objet instance est lu à chaque fois à partir de la mémoire principale, ce qui permet d'utiliser la syntaxe DCL pour réaliser le modèle singleton. Bien sûr, volatile affectera un peu les performances, mais en considérant la correction du programme, cette perte de performance vaut la peine.
Avantages:La taux d'utilisation des ressources est élevé, l'objet singleton n'est instance que lors de l'exécution de getInstance pour la première fois, ce qui est efficace. Dans des situations où le volume de concurrence n'est pas élevé et la sécurité n'est pas élevée, le modèle singleton peut fonctionner parfaitement.
Inconvénients:La réaction est un peu lente au premier chargement, et cela peut également échouer occasionnellement en raison du modèle de mémoire Java. Il a également certains défauts dans un environnement à haut débit, bien que la probabilité soit très faible.
Complément:Dans le projet open source d'image Android-Universel-Image-Loader (https://github.com/nostra13/Android-Universel-Image-Loader)qui utilise cette méthode.
Le modèle DCL est la manière la plus courante d'implémenter le singleton, il peut instance le singleton à l'heure nécessaire et peut garantir l'unicité de l'objet singleton dans la plupart des scénarios, sauf si votre code est complexe en mode concurrent ou inférieur à JDK6Version d'utilisation, sinon, cette méthode peut généralement répondre aux besoins.
4、Modèle singleton de classe interne statique
DCL, bien que dans une certaine mesure il résolve les problèmes de consommation de ressources, de synchronisation superflue, de sécurité des threads, etc., mais il reste que dans certaines situations, il peut échouer. Ce problème est appelé échec du verrouillage double vérification (DCL), qui est discuté dans le dernier livre "Pratique de programmation concurrente en Java", et il est indiqué que cette "optimisation" est laide et non recommandée. Au lieu de cela, il est recommandé d'utiliser le code suivant :
Exemple de code :
/** * Modèle singleton de classe interne statique */ public class Singleton { private Singleton(){} public static Singleton getInstance(){ return SingletonHolder.instance; } /** * Classe interne statique * Chargement différé, réduction des coûts de mémoire */ private static class SingletonHolder{}} private static final Singleton instance = new Singleton(); } }
Lorsque la classe Singleton est chargée pour la première fois, instance n'est pas initialisée, mais n'est initialisée que lors de la première appel de la méthode getInstance de Singleton. Par conséquent, la première appel de getInstance entraînera le chargement de la classe SingletonHolder par le JVM, ce qui non seulement assure la sécurité des threads, mais aussi garantit l'unicité de l'objet singleton, et décale également l'instanciation du singleton, donc c'est une méthode d'implémentation de pattern singleton recommandée.
Avantages: chargement différé, thread-safe (mutuellement exclusif lors du chargement de la classe dans java), et réduit également la consommation de mémoire
5, singleton enum
J'ai expliqué quelques implémentations du pattern singleton, mais, ces implémentations ne sont pas sans problème ou elles présentent des problèmes dans certaines situations.
Exemple de code :
/** * le pattern singleton enum */ public enum Singleton { /** * 1. à partir de Java1.5commence à soutenir; * 2. fournir gratuitement le mécanisme de sérialisation; * 3. absolument éviter la réinstanciation multiple, même en présence d'attaques de sérialisation ou de réflexion complexes; */ instance; private String others; Singleton() { } public String getOthers() { return others; } public void setOthers(String others) { this.others = others; } }
La simplicité de la syntaxe est le plus grand avantage du singleton enum, l'enum en Java est identique à une classe ordinaire, il peut non seulement avoir des champs, mais aussi ses propres méthodes. Ce qui est le plus important, la création par défaut des instances d'enum est thread-safe et est toujours un singleton dans toutes les situations.
Pourquoi dijon cela ? Dans les différentes implémentations du pattern singleton mentionnées ci-dessus, il y a un cas où ils créent à nouveau l'objet, c'est la désérialisation.
La sérialisation permet d'écrire une instance d'objet singleton sur le disque, puis de la lire à nouveau, permettant ainsi d'obtenir une instance de manière efficace. Même si le constructeur est privé, il est possible de créer une nouvelle instance de la classe par un moyen spécial lors de la désérialisation, ce qui équivaut à appeler le constructeur de la classe. L'opération de désérialisation fournit une fonction钩子 spéciale, une méthode privée et instanciée readResolve() dans la classe, qui permet aux développeurs de contrôler la désérialisation de l'objet. Par exemple, si l'on souhaite éviter que l'objet singleton ne soit réinitialisé lors de la désérialisation, il est nécessaire d'ajouter la méthode suivante :
private Object readResolve() throws ObjectStreamException { return instance; }
c'est-à-dire que l'objet instance est renvoyé dans la méthode readResolve, au lieu de générer un nouveau objet par défaut. Pour les enums, ce problème n'existe pas, car même après la désérialisation, ils ne génèrent pas de nouvelles instances.
Avantagesdepuis Java
Inconvénientsdepuis Java1.5commence à prendre en charge.
Nous avons principalement discuté du modèle Singleton ci-dessus5méthodes de création, vous pouvez les utiliser dans vos projets personnels en fonction de leurs avantages et inconvénients.
Les lecteurs intéressés par plus de contenu sur Android peuvent consulter les sujets spéciaux de ce site : "Introduction et tutoriel avancé de développement Android", "Conseils de débogage et solutions de problèmes courants pour Android", "Résumé des utilisations des composants de base Android", "Résumé des techniques de vue View Android", "Résumé des techniques de layout Android" et "Résumé des utilisations des contrôles Android"
J'espère que la description de cet article vous sera utile pour la conception de programmes Android.
Déclaration : le contenu de cet article est tiré d'Internet, la propriété intellectuelle appartient à ses auteurs respectifs, le contenu est apporté par les utilisateurs d'Internet de manière spontanée et auto-proposée, ce site ne détient pas de propriété intellectuelle, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique connexe. Si vous trouvez du contenu suspect de violation de droits d'auteur, veuillez envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois confirmée, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.)