1. Was ist ein Designmuster
In der Software -Engineering ist das Designmuster eine Lösung, die verschiedenen allgemeinen (wiederkehrenden) Problemen im Softwaredesign vorgeschlagen wird. Dieser Begriff wurde in den neunziger Jahren von Erich Gamma und anderen in die Informatik aus dem Gebiet des architektonischen Designs eingeführt.
Berühmte 4-Personen-Bande: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (GOF)
Designmuster: Die Grundlagen wiederverwendbarer objektorientierter Software
2. Singleton -Modus
Die Klasse eines Singleton -Objekts muss garantiert nur eine Instanz haben. Oft muss das gesamte System nur über ein globales Objekt verfügen, was unserer Koordination des Gesamtverhaltens des Systems förderlich ist.
Zum Beispiel: Globale Informationskonfiguration
Die einfachste Implementierung des Singleton -Modus:
öffentliche Klasse Singleton {private Singleton () {System.out.println ("Singleton is Create"); } private statische Singleton Instance = new Singleton (); public static singleton getInstance () {return Instance; }} Die Einzigartigkeit wird durch den privaten Konstruktor und statisch bestimmt.
Nachteile: Wenn eine Instanz generiert wird, ist es schwer zu kontrollieren
Obwohl wir wissen, dass beim ersten geladenen Klassen Singleton eine Instanz generiert wird.
Aber wenn es in dieser Klasse andere Eigenschaften gibt
öffentliche Klasse Singleton {public static int Status = 1; private Singleton () {System.out.println ("Singleton is Create"); } private statische Singleton Instance = new Singleton (); public static singleton getInstance () {return Instance; }} Bei Verwendung
System.out.println (Singleton.status);
Dieses Beispiel wird produziert. Vielleicht möchten Sie nicht, dass diese Instanz zu diesem Zeitpunkt generiert wird.
Wenn das System auf dieses Problem besondere Aufmerksamkeit schenkt, ist die Implementierungsmethode dieses Singleton nicht sehr gut.
Die Lösung für den zweiten Singleton -Modus:
öffentliche Klasse Singleton {private Singleton () {System.out.println ("Singleton is Create"); } private statische Singleton Instance = NULL; public static synchronisierte Singleton getInstance () {if (instance == null) instance = new Singleton (); Rückkehrinstanz; }} Sei Instanz nur dann, wenn die GetInstance () -Methode aufgerufen wird und die Gewindesicherheit durch synchronisiert wird.
Dies kontrolliert, wenn Instanzen erstellt werden.
Dieser Ansatz ist typisch für faule Laden.
Ein Problem ist jedoch, dass die Leistung einen Einfluss auf hohe Parallelitätsszenarien hat. Obwohl es mit nur einem Urteil zurückgegeben wird, wird es bei hoher Genauigkeit einen Einfluss haben.
Um effizient zu sein, gibt es eine dritte Methode:
public class staticsingleton {private Staticsingleton () {System.out.println ("Staticsingleton create"); } private statische Klasse Singletonholder {private static Staticsingleton Instance = new Staticsingleton (); } public static Staticsingleton getInstance () {return Singletonholder.instance; }} Da eine Klasse geladen ist, wird die innere Klasse nicht geladen. Dies stellt sicher, dass die Instanz nur dann generiert wird, wenn GetInstance () aufgerufen wird, die Zeit der Erzeugung der Instanz kontrolliert und die verzögerte Belastung erreicht wird.
Und synchronisiert wird entfernt, um die Leistung zu verbessern, und statisch wird verwendet, um die Einzigartigkeit zu gewährleisten.
3.. Invariante Modus
Nachdem der interne Zustand einer Klasse geschaffen wurde, wird sie sich während der gesamten Lebenszeit nicht ändern.
Der Unchange -Modus erfordert keine Synchronisation
Erstellen Sie eine unveränderte Klasse:
Public Final Class Product {// Stellen Sie sicher, dass es keine private Subklasse gibt. // private Attribute werden nicht von anderen Objekten erhalten. Der private endgültige Zeichenfolge Name; // endgültige Garantien, dass das Attribut nicht zweimal privater Doppelpreise zugewiesen wird. Öffentliches Produkt (Zeichenfolge Nr., String -Name, Doppelpreis) {// beim Erstellen eines Objekts müssen die Daten super () angegeben werden; // Weil nach der Erstellung nicht modifiziert werden kann.no = no; this.name = name; this.price = Preis; } public String getNo () {return no; } public String getName () {return name; } public double getPrice () {Rückgabepreis; }} Zu den Fällen unveränderlicher Muster in Java gehören:
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. zukünftiger Modus
Die Kernidee sind asynchrone Anrufe
Nicht asynchron:
asynchron:
Der erste Call_Return wird zurückgegeben, da die Aufgabe noch nicht erledigt wurde.
Diese Renditen ähneln jedoch einer Bestellung beim Einkaufen, und Sie können ein Ergebnis basierend auf dieser Bestellung in Zukunft erzielen.
Dieses zukünftige Modell bedeutet also, dass "Zukunft" erhalten werden kann, was bedeutet, dass die Bestellung oder der Vertrag das "Versprechen" ist und das Ergebnis in Zukunft liefern wird.
Einfache Implementierung des zukünftigen Modus:
Was der Anrufer erhält, ist eine Daten, die zu Beginn ein futuredata sein kann, da Readata nur langsam baut. Irgendwann in der Zukunft kann Readata über Futureedata erhalten werden.
Code -Implementierung:
öffentliche Schnittstellendaten {public String getResult (); } public class futureedata implementiert Daten {protected Readata realdata = null; // futureedata ist eine Readata -Wrapper -geschützte boolean isReady = false; public synchronisierte void setRealData (realdata realdata) {if (isReady) {return; } this.Realdata = realdata; isReady = wahr; notifyAll (); // Realdata wurde injiziert, benachrichtigen Sie GetResult ()} public Synchronisierte String getResult () // wird warten, bis die Readata -Konstruktion abgeschlossen ist. // Warten Sie die ganze Zeit, um zu wissen, dass Readata injiziert wird} catch (InterruptedException e) {}} return readata.result; // implementiert von Readata}} öffentliche Klasse Readata implementiert Daten {geschütztes endgültiges String -Ergebnis; public readata (String para) {// Die Konstruktion von Readata kann sehr langsam sein und verlangt, dass der Benutzer lange warten muss. Hier simulieren wir den Schlaf, um StringBuffer sb = new StringBuffer () zu simulieren. für (int i = 0; i <10; i ++) {sb.append (para); Versuchen Sie es hier anstelle eines sehr langsamen Betriebs -Threads. Sleep (100); } catch (InterruptedException e) {}} result = sb.toString (); } public String getResult () {Rückgabeergebnis; }} public class Client {öffentliche Datenanforderung (endgültige String queryStr) {endgültig futureedata future = new futureedata (); neuer Thread () {public void run () {// realdata ist sehr langsam zu bauen, // so reformata in einem separaten Thread realdata = new Readata (querystr); Future.setRealData (Realdata); } } }.Start(); Zukunft zurückgeben; // futureedata wird sofort zurückgegeben}} public static void main (string [] args) {client client = new Client (); // Dies wird sofort zurückgegeben, da das, was Sie erhalten, futuredata anstelle von Readata data = client.request ("Name"); System.out.println ("Anfrage abgeschlossen"); Versuchen Sie es mit {// hier können Sie einen Schlaf verwenden, anstatt andere Geschäftslogiken zu verarbeiten // Bei der Verarbeitung dieser Geschäftslogik wird Realdata erstellt, wodurch der Wartezeit -Thread.sleep (2000) voll ausgeht. } catch (InterruptedException e) {} // Real Data System.out.println ("data =" + data.getResult ()); }Es gibt auch viele zukünftige Modusunterstützung in JDK:
Verwenden Sie als nächstes die von JDK bereitgestellten Klassen und Methoden, um den Code gerade zu implementieren:
importieren java.util.concurrent public readata (String para) {this.para = para; } @Override public String call () löst Ausnahme aus {stringBuffer sb = new StringBuffer (); für (int i = 0; i <10; i ++) {sb.append (para); try {thread.sleep (100); } catch (InterruptedException e) {}} return sb.toString (); }} importieren java.util.concurrent.executionException; import java.util.concurrent Futuretask futuretask <string> future = new futuretask <string> (new RealData ("a")); ExecutorService Executor = Executors.NewFixedThreadpool (1); // Futuretask ausführen, äquivalent zu Client.request ("a") im obigen Beispiel senden // den Thread hier aktivieren, um Readata Call () auszuführen und executor.submit (Future) auszuführen; System.out.println ("Anfrage abgeschlossen"); Versuchen Sie es mit {// zusätzliche Datenvorgänge können hier weiterhin durchgeführt werden, und der Schlaf kann verwendet werden, anstatt andere Geschäftslogik -Threads zu verarbeiten. Sleep (2000); } catch (interruptedException e) {} // äquivalent zu Data.getResult (), erhalten Sie den Rückgabewert der CALL () -Methode // Wenn die CALL () -Methode zu diesem Zeitpunkt nicht ausgeführt wird, wartet sie weiterhin auf System.out.println ("Data =" + Future.get ()); }} Was Sie hier beachten müssen, ist, dass Futuretask eine Klasse ist, die zukünftige Funktionen und Funktionen hat. So kann es wieder laufen und es schließlich bekommen.
Wenn die tatsächlichen Daten nicht fertig sind, wenn sie Future.get () anrufen, wird dies natürlich zu einer Blockierungssituation führen, bis die Daten fertig sind.
Natürlich gibt es einfachere Möglichkeiten:
importieren java.util.concurrent.executionException; import java.util.concurrent Executors.NewFixed threadpool (1); // Futuretask ausführen, äquivalent zu client.request ("a") im obigen Beispiel Senden Sie eine Anforderung // Öffnen Sie den Thread hier, um Readata Call () durchzuführen und Future <string> Future = Executor.Submit (neuer Readata ("A") auszuführen. System.out.println ("Anfrage abgeschlossen"); Versuchen Sie {// zusätzliche Datenvorgänge können hier weiterhin durchgeführt werden. Verwenden Sie den Schlaf anstelle eines anderen Geschäfts logischen Verarbeitungs -Threads.sleep (2000); } catch (interruptedException e) {} // äquivalent zu data.getResult (), erhalten Sie den Rückgabewert der CALL () -Methode // Wenn die CALL () -Methode zu diesem Zeitpunkt nicht ausgeführt wird, wartet system.out.println weiterhin auf System.out.println ("Data =" + Future.get ()); }} Da Callable einen Rückgabewert hat, können Sie das zukünftige Objekt direkt zurückgeben.
5. Produzent und Verbraucher
Das Produzent-Verbrauchermodell ist ein klassisches Design-Designmodell mit Multi-Threaded. Es bietet eine gute Lösung für die Zusammenarbeit zwischen mehreren Threads. Im Hersteller-Verbrauchermodell gibt es normalerweise zwei Arten von Threads, nämlich mehrere Produzentenfäden und mehrere Verbraucherfäden. Der Hersteller -Thread ist für die Übermittlung von Benutzeranfragen verantwortlich, während der Verbraucher -Thread für die spezifische Umstellung der vom Produzenten eingereichten Aufgaben verantwortlich ist. Der Produzent und der Verbraucher kommunizieren durch einen gemeinsamen Speicherpuffer.
Ich habe in der Vergangenheit einen Artikel geschrieben, um verschiedene Methoden zur Verwendung von Java zur Implementierung von Produzenten und Verbrauchern zu implementieren, daher werde ich ihn hier nicht erklären.