1. ¿Qué es un patrón de diseño?
En ingeniería de software, el patrón de diseño es una solución propuesta para varios problemas comunes (recurrentes) en el diseño de software. Este término fue introducido en informática desde el campo del diseño arquitectónico en la década de 1990 por Erich Gamma y otros.
Famosa pandilla de 4 personas: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (GOF)
Patrón de diseño: los conceptos básicos del software reutilizable orientado a objetos
2. Modo Singleton
Se debe garantizar que la clase de un objeto singleton tenga solo una instancia. Muchas veces todo el sistema solo necesita tener un objeto global, lo que conduce a nuestra coordinación del comportamiento general del sistema.
Por ejemplo: Configuración de información global
La implementación más simple del modo singleton:
public class Singleton {private Singleton () {System.out.println ("Singleton es creación"); } instancia de singleton static privada = new Singleton (); public static singleton getInstance () {instancia de retorno; }} La singularidad está determinada por el constructor privado y la estática.
Desventajas: cuando se genera una instancia es difícil de controlar
Aunque sabemos que cuando la clase Singleton se carga por primera vez, se genera una instancia.
Pero si hay otras propiedades en esta clase
clase pública Singleton {public static int status = 1; private singleton () {System.out.println ("Singleton Is Create"); } instancia de singleton static privada = new Singleton (); public static singleton getInstance () {instancia de retorno; }} Al usar
System.out.println (Singleton.status);
Este ejemplo se produce. Tal vez no quieras que se genere esta instancia en este momento.
Si el sistema presta especial atención a este problema, el método de implementación de este singleton no es muy bueno.
La solución al segundo modo singleton:
public class Singleton {private Singleton () {System.out.println ("Singleton es creación"); } instancia de singleton estático privado = nulo; public static sincronizado sincronizado getInstance () {if (instance == null) instancia = new Singleton (); instancia de retorno; }} Deje que se cree la instancia solo cuando se llame el método getInstance (), y la seguridad de los subprocesos se garantiza a través de sincronizado.
Esto controla cuando se crean instancias.
Este enfoque es típico de la carga perezosa.
Pero un problema es que el rendimiento tendrá un impacto en escenarios de alta concurrencia. Aunque se devuelve con solo un juicio, tendrá un impacto en el caso de alta concurrencia, tendrá un impacto más o menos porque debe obtener el bloqueo sincronizado.
Para ser eficiente, hay un tercer método:
Public Class STATICSINGLETON {private staticsingleton () {system.out.println ("STISTICSINGLETON es creando"); } clase privada de clase static singletonholder {private static staticsingleton instancia = new staticsingleton (); } public static staticsingleton getInstance () {return singletonholder.instance; }} Desde que se carga una clase, su clase interna no se cargará. Esto asegura que la instancia se generará solo cuando se llame GetInstance (), se controla el tiempo de generación de la instancia y se logra la carga retrasada.
Y sincronizado se elimina para mejorar el rendimiento y se utiliza estática para garantizar la singularidad.
3. Modo invariante
Después de crear el estado interno de una clase, no cambiará durante todo el período de la vida.
El modo de cambio no requiere sincronización
Crear una clase sin cambios:
Producto de clase final pública {// Asegúrese de que no haya una cadena final privada de subclase no; // Los atributos privados no serán obtenidos por otros objetos Nombre de cadena final privada; // Garantías finales que el atributo no se asignará dos veces el precio doble privado; PRODUCTO PÚBLICO (String NO, Nombre de cadena, doble precio) {// Al crear un objeto, los datos deben especificarse super (); // Porque después de la creación, no se puede modificar esto.no = no; this.name = name; this.price = precio; } public String getNo () {return no; } public String getName () {nombre de retorno; } public Double GetPrice () {Return Price; }} Los casos de patrones sin cambios en Java incluyen:
java.lang.string
java.lang.boolean
java.lang.byte
java.lang.caracter
java.lang.double
java.lang.float
java.lang.integer
java.lang.long
java.lang.short
4. Modo futuro
La idea central son las llamadas asíncronas
No asincrónico:
asincrónico:
El primer call_return se devuelve ya que la tarea aún no se ha completado.
Pero estas devoluciones son similares a un pedido de compras, y puede obtener un resultado basado en este pedido en el futuro.
Entonces, este modelo futuro significa que se puede obtener "futuro", lo que significa que el orden o el contrato es la "promesa" y dará el resultado en el futuro.
Implementación simple del modo futuro:
Lo que la persona que llama obtiene son datos, que pueden ser una futura al principio, porque RealData es lento para construir. En algún momento en el futuro, RealData se puede obtener a través de Futuredata.
Implementación del código:
Datos de interfaz pública {public String getResult (); } public class futuredata implementa datos {protegido realData realData = null; // futuredata es un booleano protegido por envoltura de realado isready = false; public sincronizado sincronizado setrealData (realData realData) {if (isReady) {return; } this.realData = realData; iSready = True; notifyall (); // RealData ha sido inyectado, notifique a getResult ()} public sincronizado String getResult () // Esperará a que la construcción de Realdata complete {while (! Isready) {try {wait (); // Espera todo el tiempo para saber que RealData se inyecta} Catch (InterruptedException e) {}} return realData.result; // implementado por RealData}} public class RealData implementa datos {resultado de cadena final protegida; Public RealData (String para) {// La construcción de RealData puede ser muy lenta y requiere que el usuario espere mucho tiempo. Aquí usamos el sueño para simular StringBuffer sb = new StringBuffer (); para (int i = 0; i <10; i ++) {sb.append (párra); intente {// use el sueño aquí en lugar de una operación muy lenta. } capt (interruptedException e) {}} result = sb.ToString (); } public String getResult () {return resultado; }} Public Class Client {Public Data Soly (Final String Qerystr) {Final Futuredata Future = new Futuredata (); New Thread () {public void run () {// realData es muy lento para construir, // así realData en un hilo separado realData = new RealData (QueryStr); futuro.setrealData (realData); } } }.comenzar(); regresar futuro; // futuredata se devolverá inmediatamente}} public static void main (string [] args) {Client cliente = new Client (); // Esto se devolverá inmediatamente porque lo que obtiene es futuredata en lugar de data data data = client.request ("nombre"); System.out.println ("solicitud completada"); Pruebe {// Aquí puede usar un sueño en lugar de procesar otras lógicas comerciales // En el proceso de procesamiento de esta lógica comercial, se crea RealData, haciendo que el tiempo de espera del hilo de espera. Sleep (2000); } Catch (InterruptedException e) {} // use datos reales system.out.println ("data =" + data.getResult ()); }También hay muchos soportes de modo futuro en JDK:
A continuación, use las clases y métodos proporcionados por JDK para implementar el código en este momento:
import java.util.concurrent.callable; public class RealData implementa Callable <String> {private String para; public realdata (String para) {this.para = para; } @Override public String Call () lanza la excepción {StringBuffer sb = new StringBuffer (); para (int i = 0; i <10; i ++) {sb.append (párra); intente {thread.sleep (100); } capt (interruptedException e) {}} return sb.ToString (); }} import java.util.concurrent.ExecutionException; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.futureTask; public class Futuremain {public estatic estatic our (] args) lanza InterruptedException, ExecutiCeption { / ///////// / público. FUTURETASK FUTURETASK <String> Future = new FutureTask <String> (new RealData ("A")); EjecutorService Ejecutor = Ejecutors.NewFixedThreadPool (1); // Ejecutar FutUreTask, equivalente a Client.Request ("A") En el ejemplo anterior, envíe una solicitud // Habilitar el hilo aquí para realizar una llamada de RealData () y ejecutar Executor.submit (Future); System.out.println ("solicitud completada"); Pruebe {// todavía se pueden realizar operaciones de datos adicionales, y el sueño se puede usar en lugar de procesar otros hilos lógicos de negocios. Sleep (2000); } capt (interruptedException e) {} // equivalente a data.getResult (), obtenga el valor de retorno del método de llamada () // Si el método de llamada () no se ejecuta en este momento, aún esperará system.out.println ("data =" + futuro.get ()); }} Lo que debe tener en cuenta aquí es que FutureTask es una clase que tiene función futura y función ejecutable. Entonces puede volver a funcionar y finalmente obtenerlo.
Por supuesto, si los datos reales no están listos al llamar a Future.get (), aún causará una situación de bloqueo hasta que los datos estén listos.
Por supuesto que hay formas más fáciles:
import 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 InterruptedException, ExecutionException { ExecutorService executor = Ejecutores.newFixedThreadPool (1); // Ejecutar FutUreTask, equivalente a Client.Request ("A") En el ejemplo anterior, envíe una solicitud // Abra el hilo aquí para realizar la llamada de RealData () y ejecute Future <String> Future = Executor.submit (new RealData ("A")); System.out.println ("solicitud completada"); Pruebe {// Las operaciones de datos adicionales aún se pueden hacer aquí, use el sueño en lugar de otro hilo de procesamiento de lógica comercial. Sleep (2000); } capt (interruptedException e) {} // equivalente a data.getResult (), obtenga el valor de retorno del método call () // si el método call () no se ejecuta en este momento, system.out.println seguirá esperando sistem.out.println ("data =" + futuro.get ()); }} Dado que Callable tiene un valor de retorno, puede devolver directamente el objeto futuro.
5. Productor y consumidor
El modelo de consumidor de productores es un modelo de diseño clásico de múltiples subprocesos. Proporciona una buena solución para la colaboración entre múltiples hilos. En el modelo de consumidor de productores, generalmente hay dos tipos de hilos, a saber, varios hilos de productores y varios hilos de consumo. El hilo del productor es responsable de enviar solicitudes de usuario, mientras que el hilo del consumidor es responsable de manejar específicamente las tareas presentadas por el productor. El productor y el consumidor se comunican a través de un búfer de memoria compartida.
He escrito un artículo en el pasado para implementar varios métodos para usar Java para implementar productores y consumidores, por lo que no lo explicaré aquí.