1. Qu'est-ce qu'un motif de conception
En génie logiciel, le modèle de conception est une solution proposée à divers problèmes courants (récurrents) dans la conception des logiciels. Ce terme a été introduit dans l'informatique depuis le domaine de la conception architecturale dans les années 1990 par Erich Gamma et autres.
Gang célèbre de 4 personnes: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (GoF)
Modèle de conception: les bases du logiciel orienté objet réutilisable
2. Mode singleton
La classe d'un objet Singleton doit être garantie pour ne pas avoir une seule instance. Plusieurs fois, l'ensemble du système ne doit avoir qu'un seul objet global, ce qui est propice à notre coordination du comportement global du système.
Par exemple: configuration d'informations globales
L'implémentation la plus simple du mode Singleton:
classe publique singleton {private singleton () {System.out.println ("Singleton is Create"); } Instance singleton statique privée = new Singleton (); public static singleton getInstance () {return instance; }} Le caractère unique est déterminé par le constructeur privé et statique.
Inconvénients: lorsqu'une instance est générée est difficile à contrôler
Bien que nous sachions que lorsque la classe Singleton est chargée pour la première fois, une instance est générée.
Mais s'il y a d'autres propriétés dans cette classe
classe publique Singleton {public static int status = 1; privé singleton () {System.out.println ("Singleton is Create"); } Instance singleton statique privée = new Singleton (); public static singleton getInstance () {return instance; }} Lors de l'utilisation
System.out.println (singleton.status);
Cet exemple est produit. Peut-être que vous ne voulez pas que cette instance soit générée pour le moment.
Si le système accorde une attention particulière à ce problème, la méthode de mise en œuvre de ce singleton n'est pas très bonne.
La solution au deuxième mode singleton:
classe publique singleton {private singleton () {System.out.println ("Singleton is Create"); } Instance singleton statique privée = null; public static synchronisé singleton getInstance () {if (instance == null) instance = new singleton (); retour d'instance; }} Que l'instance soit créée uniquement lorsque la méthode getInstance () est appelée et que la sécurité des filetages est assurée par synchronisé.
Cela contrôle lorsque des instances sont créées.
Cette approche est typique du chargement paresseux.
Mais un problème est que les performances auront un impact sur des scénarios de concurrence élevés. Bien qu'il soit renvoyé avec un seul jugement, il aura un impact dans le cas d'une concurrence élevée, il aura un impact plus ou moins car vous devez obtenir le verrou synchronisé.
Pour être efficace, il existe une troisième méthode:
classe publique StateticsIngleton {private statisticsingleton () {System.out.println ("Statisticsingleton is Create"); } classe statique privée singletonHolder {instruments statiques privés Instance = new StateSingleton (); } public static staticsingleton getInstance () {return singletonholder.instance; }} Étant donné qu'une classe sera chargée, sa classe intérieure ne sera pas chargée. Cela garantit que l'instance ne sera générée que lorsque getInstance () est appelée, le temps de génération de l'instance est contrôlé et le chargement retardé est obtenu.
Et synchronisé est supprimé pour améliorer les performances et statique est utilisée pour assurer le caractère unique.
3. Mode invariant
Une fois l'état interne d'une classe créée, il ne changera pas pendant toute la période de vie.
Le mode Unchange ne nécessite pas de synchronisation
Créez une classe inchangée:
Produit de classe finale publique {// Assurez-vous qu'il n'y a pas de chaîne finale privée sous-classe no; // Les attributs privés ne seront pas obtenus par d'autres objets Nom de la chaîne finale privée; // garantit final que l'attribut ne sera pas attribué deux fois à double prix privé; Produit public (chaîne no, nom de chaîne, double prix) {// Lors de la création d'un objet, les données doivent être spécifiées super (); // Parce qu'après la création, il ne peut pas être modifié ce.no = non; this.name = name; this.price = prix; } public String getno () {return non; } public String getName () {Nom de retour; } public double getPrice () {prix de retour; }} Les cas de modèles immuables en Java comprennent:
java.lang.string
java.lang.boolean
java.lang.byte
java.lang.character
java.lang.double
java.lang.float
java.lang.integer
java.lang.long
java.lang.short
4. Mode futur
L'idée principale est les appels asynchrones
Non-asynchrone:
asynchrone:
Le premier call_return est retourné car la tâche n'est pas encore terminée.
Mais ces rendements sont similaires à une commande dans les achats, et vous pouvez obtenir un résultat en fonction de cette commande à l'avenir.
Ainsi, ce futur modèle signifie que «l'avenir» peut être obtenu, ce qui signifie que l'ordre ou le contrat est la «promesse» et donnera le résultat à l'avenir.
Implémentation simple du mode futur:
Ce que l'appelant obtient, ce sont des données, qui peuvent être un futureData au début, car RealData est lent à construire. À un moment donné dans le futur, Realdata peut être obtenu via Futuredata.
Implémentation du code:
Données d'interface publique {public String getResult (); } classe publique FutureData implémente les données {protégé realData realData = null; // futureData est un wrapper realdata protégée booléen isReady = false; public synchronisé void setRealData (realData realData) {if (iSready) {return; } this.realdata = realData; IsReady = true; notifyall (); // realData a été injecté, notifier getResult ()} chaîne publique synchronisée getResult () // attendra que la construction realData termine {while (! IsReady) {try {wait (); // attendez tout le temps pour savoir que realData est injecté} catch (InterruptedException e) {}} return realData.result; // implémenté par realData}} classe publique RealData implémente les données {le résultat de la chaîne finale protégé; Public RealData (String Para) {// La construction de RealData peut être très lente et oblige l'utilisateur à attendre longtemps. Ici, nous utilisons le sommeil pour simuler StringBuffer SB = new StringBuffer (); pour (int i = 0; i <10; i ++) {sb.append (para); Essayez {// Utilisez le sommeil ici au lieu d'un fonctionnement très lent. Sleep (100); } catch (InterruptedException e) {}} result = sb.toString (); } public String getResult () {return result; }} Client de classe publique {Public Data Request (Final String QueryStr) {Final FutureData future = new FutureData (); nouveau thread () {public void run () {// realData est très lent à construire, // So realData dans un thread séparé realData = new realData (queryStr); futur.setRealData (realdata); } } }.commencer(); retour à l'avenir; // FutureData sera renvoyé immédiatement}} public static void main (String [] args) {client client = new client (); // Ceci sera renvoyé immédiatement parce que ce que vous obtenez est futureData au lieu de realData data data = client.request ("name"); System.out.println ("Demande terminée"); Essayez {// ici, vous pouvez utiliser un sommeil au lieu de traiter d'autres logiques commerciales // Dans le processus de traitement de ces logiques métier, RealData est créée, utilisant pleinement le temps d'attente.Sleep (2000); } catch (InterruptedException e) {} // Utiliser Real Data System.out.println ("data =" + data.getResult ()); }Il existe également de nombreux modes futurs dans JDK:
Ensuite, utilisez les classes et méthodes fournies par JDK pour implémenter le code tout à l'heure:
import java.util.concurrent.callable; public class realData implémente callable <string> {private String para; public realData (String Para) {this.para = para; } @Override public String Call () lève une exception {StringBuffer sb = new StringBuffer (); pour (int i = 0; i <10; i ++) {sb.append (para); essayez {thread.sleep (100); } catch (InterruptedException e) {}} return sb.toString (); }} Importer java.util.concurrent.executionException; Importer java.util.concurrent.execcutorService; import java.util.concurrent.executors; importer java.util.concurrent.futuretask; public class Futuremain {public static void main (strigs) lasters FutureTask <string> futur = new FutureTask <string> (new realData ("a")); ExecutorService exécutor = exécutor.NewFixEdThreadPool (1); // Exécuter FutureTask, équivalent à client.Request ("A") Dans l'exemple ci-dessus, envoyez une demande // activer le thread ici pour effectuer RealData Call () et exécuter EMECTOROR.SUBMIT (Future); System.out.println ("Demande terminée"); Essayez {// des opérations de données supplémentaires peuvent toujours être effectuées ici, et le sommeil peut être utilisé au lieu de traiter un autre thread logique métier.Sleep (2000); } catch (InterruptedException e) {} // équivalent à data.getResult (), obtenez la valeur de retour de la méthode Call () // Si la méthode Call () n'est pas exécutée pour le moment, elle attendra toujours System.out.println ("data =" + future.get ()); }} Ce que vous devez noter ici, c'est que FutureTask est une classe qui a une fonction future et une fonction exécutable. Il peut donc courir à nouveau et enfin l'obtenir.
Bien sûr, si les données réelles ne sont pas prêtes lors de l'appel Future.get (), cela entraînera toujours une situation de blocage jusqu'à ce que les données soient prêtes.
Bien sûr, il existe des moyens plus faciles:
Importer java.util.concurrent.executionException; import java.util.concurrent.executorService; import java.util.concurrent.executors; import java.util.concurrent.future; public class Futuremain2 {public static void main (String [] args) throws throws interruptedException, exitionException {Examponervice Exle exécutory Exécutors.NewFixEdThreadpool (1); // Exécuter FutureTask, équivalent à client.Request ("A") Dans l'exemple ci-dessus, envoyez une demande // Ouvrez le thread ici pour effectuer RealData Call () et exécuter Future <string> futur = EMEMPOROR.SUBMIT (new realData ("A")); System.out.println ("Demande terminée"); Essayez {// des opérations de données supplémentaires peuvent toujours être effectuées ici, utilisez le sommeil au lieu des autres fonctionnalités de traitement de la logique métier.Sleep (2000); } catch (InterruptedException e) {} // équivalent à data.getResult (), obtenez la valeur de retour de la méthode d'appel () // Si la méthode Call () ne s'exécute pas pour le moment, System.out.println attendra toujours System.out.println ("data =" + future.get ()); }} Étant donné que Calable a une valeur de retour, vous pouvez directement renvoyer l'objet futur.
5. Producteur et consommateur
Le modèle producteur-consommateur est un modèle de conception multi-thread classique. Il fournit une bonne solution pour la collaboration entre plusieurs threads. Dans le modèle producteur-consommateur, il existe généralement deux types de threads, à savoir plusieurs threads producteur et plusieurs threads de consommation. Le fil du producteur est responsable de la soumission des demandes des utilisateurs, tandis que le thread de consommation est responsable de la gestion spécifique des tâches soumises par le producteur. Le producteur et le consommateur communiquent via un tampon de mémoire partagé.
J'ai écrit un article dans le passé pour mettre en œuvre diverses méthodes d'utilisation de Java pour implémenter les producteurs et les consommateurs, donc je ne l'expliquerai pas ici.