concepto:
El patrón Singleton en Java es un patrón de diseño común. Singleton Pattern se divide en tres tipos: Singleton Lazy, Hungry Singleton y Singleton registrado.
El modo singleton tiene las siguientes características:
1. Solo puede haber una instancia en una clase Singleton.
2. La clase Singleton debe crear su propia instancia única.
3. La clase Singleton debe proporcionar esta instancia a todos los demás objetos.
Singleton Pattern asegura que una clase tenga solo una instancia, y la instancia misma y proporciona esta instancia a todo el sistema. En los sistemas informáticos, los objetos del controlador para grupos de roscas, cachés, objetos de registro, cuadros de diálogo, impresoras y tarjetas gráficas a menudo se diseñan como solteros. Estas aplicaciones tienen más o menos la funcionalidad de un administrador de recursos. Cada computadora puede tener varias impresoras, pero solo puede estar disponible una bobina de impresora para evitar que se emitan dos trabajos de impresión a la impresora al mismo tiempo. Cada computadora puede tener varios puertos de comunicación, y el sistema debe administrar centralmente estos puertos de comunicación para evitar que un puerto de comunicación se llame simultáneamente por dos solicitudes. En resumen, elegir un modelo singleton es evitar estados inconsistentes y evitar el optimismo político.
Aquí hay dos tipos de presentaciones: perezoso y hambriento
1. Cargar inmediatamente/estilo hambriento
Antes de llamar al método, se ha creado la instancia, código:
paquete com.weishiyao.learn.day8.singleton.ep1; clase pública myObject {// carging ahora == Modo malvado MyObject MyObject MyObject = new MyObject (); Private myObject () {} public static myObject getInstance () {// Esta versión de código se está cargando ahora // La desventaja de esta versión del código es que no puede haber otras variables de instancia // porque el método getInstance () no está sincronizado //, por lo tanto, los problemas que no sean, pueden ocurrir un retorno myObject; }} Crear una clase de hilo
paquete com.weishiyao.learn.day8.singleton.ep1; public class mythread extiende el hilo {@Override public void run () {System.out.println (myObject.getInstance (). HashCode ()); }} Crea una clase de ejecución
paquete com.weishiyao.learn.day8.singleton.ep1; public class run {public static void main (string [] args) {mythread t1 = new myThread (); MyThread t2 = new MyThread (); Mythread t3 = new MyThread (); t1.start (); t2.start (); t3.start (); }} Resultados de ejecución
167772895
167772895
167772895
Hashcode es el mismo valor, lo que significa que el objeto también es el mismo, lo que significa que se implementa el modo de carga instantánea.
2. Carga perezosa/perezoso
La instancia se creará después de que se llame al método. El plan de implementación puede ser poner instanciación en el constructor sin parámetros, de modo que se cree una instancia del objeto solo cuando se llame al método. Código:
paquete com.weishiyao.learn.day8.singleton.ep2; clase pública myobject {private static myObject myObject; private myObject () {} public static myObject getInStance () {// retraso de carga if (myObject! = null) {} else {myObject = new myObject (); } return myObject; }} Crear una clase de hilo
paquete com.weishiyao.learn.day8.singleton.ep2; public class mythread extiende el hilo {@Override public void run () {System.out.println (myObject.getInstance (). HashCode ()); }} Crea una clase de ejecución
paquete com.weishiyao.learn.day8.singleton.ep2; public class run {public static void main (string [] args) {mythread t1 = new mythread (); t1.start (); }}Resultados de ejecución
167772895
Aunque se toma una instancia de un objeto, si se encuentra en un entorno múltiple, se producirán múltiples instancias, lo que no es un patrón singleton
Ejecutar la clase de prueba
paquete com.weishiyao.learn.day8.singleton.ep2; public class run {public static void main (string [] args) {mythread t1 = new mythread (); MyThread t2 = new MyThread (); Mythread t3 = new MyThread (); Mythread t4 = new MyThread (); Mythread t5 = new MyThread (); t1.start (); t2.start (); t3.start (); t4.Start (); t5.Start (); }}Resultados de ejecución
980258163
1224717057
1851889404
188820504
1672864109
Como hay un problema, necesitamos resolver el problema. Solución múltiple en modo perezoso, código:
La primera solución, más comúnmente, se sincronizada y sincronizada se puede agregar a diferentes posiciones
El primer método bloquea
paquete com.weishiyao.learn.day8.singleton.ep3; clase pública myobject {private static myObject myObject; Private myObject () {} sincronizado public static static myObject getInstance () {// retraso de carga intente {if (myObject! = null) {} else {// simula cierta preparación antes de crear un objeto thread.sleep (2000); myObject = new MyObject (); }} catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Este esquema de sincronización sincronizado da como resultado demasiado ineficiente y todo el método está bloqueado
El segundo esquema de uso sincronizado
paquete com.weishiyao.learn.day8.singleton.ep3; clase pública myobject {private static myObject myObject; private myObject () {} public static myObject getInStance () {// retraso de carga prueba {sincronizado (myObject.class) {if (myObject! = null) {} else {// simula algunos trabajos de preparación antes de crear un objeto thread.sleep (2000); myObject = new MyObject (); }}} Catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }} Este método también es de muy baja eficiencia. Todos los códigos en el método están bloqueados. Solo necesita bloquear el código de llave. El tercer plan de uso sincronizado
paquete com.weishiyao.learn.day8.singleton.ep3;
clase pública myObject {private static myObject myObject; Private myObject () {} public static myObject getInStance () {// retraso de carga prueba {if (myObject! = null) {} else {// simula cierta preparación antes de crear el objeto Thread.sleep (2000); sincronizado (myObject.class) {myObject = new myObject (); }}} Catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Esta parece ser la mejor solución, pero después de ejecutarla, descubrí que en realidad no es seguro
resultado:
1224717057
971173439
1851889404
1224717057
1672864109
¿Por qué?
Aunque la declaración que crea un objeto está bloqueada, solo un hilo puede completar la creación a la vez, después de que llega el primer hilo para crear el objeto objeto, el segundo hilo aún puede continuar creando, porque solo bloqueamos la declaración de creación, esta solución de problema
paquete com.weishiyao.learn.day8.singleton.ep3; clase pública myobject {private static myObject myObject; private myObject () {} public static static myObject getInstance () {// retraso de carga prueba {if (myObject! = null) {} else {// simula cierta preparación antes de crear un objeto Thread.sleep (2000); sincronizado (myObject.class) {if (myObject == null) {myObject = new myObject (); }}}} Catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Simplemente agregue otro juicio a la cerradura para garantizar un singleton. Este es el mecanismo de doble verificación DCL
Los resultados son los siguientes:
1224717057
1224717057
1224717057
1224717057
1224717057
3. Use clases estáticas incorporadas para implementar casos individuales
Código principal
paquete com.weishiyao.learn.day8.singleton.ep4; clase pública myObject {// Método de clase interna Clase estática privada myobjecThandler {private static myObject myObject = new MyObject (); } public myObject () {} public static myObject getInStance () {return myobjecThandler.myObject; }} Código de clase de hilo
paquete com.weishiyao.learn.day8.singleton.ep4; public class mythread extiende el hilo {@Override public void run () {System.out.println (myObject.getInstance (). HashCode ()); }} Clase de ejecución
paquete com.weishiyao.learn.day8.singleton.ep4; public class run {public static void main (string [] args) {mythread t1 = new mythread (); MyThread t2 = new MyThread (); Mythread t3 = new MyThread (); Mythread t4 = new MyThread (); Mythread t5 = new MyThread (); t1.start (); t2.start (); t3.start (); t4.Start (); t5.Start (); }}resultado
1851889404
1851889404
1851889404
1851889404
1851889404
A través de clases estáticas internas, se obtiene un patrón singleton seguro
IV. Serializar y deserializar patrones de singleton
Las clases estáticas incorporadas pueden lograr problemas de seguridad de los subprocesos, pero si encuentra objetos serializados, el resultado obtenido utilizando el método predeterminado sigue siendo múltiples casos.
Código MyObject
paquete com.weishiyao.learn.day8.singleton.ep5; import java.io.serializable; public class myObject implementa serializable { / ** * * / private static final long serialversionUid = 888l; // Método de clase interna Clase estática privada myobjecThandler {private static myObject myObject = new MyObject (); } public myObject () {} public static myObject getInStance () {return myobjecThandler.myObject; } // myobject protegido readResolve () {// system.out.println ("El método readresolve se llamó!"); // return myobjecthandler.myobject; //}} Negocio
paquete com.weishiyao.learn.day8.singleton.ep5; import java.io.file; import java.io.fileInputStream; import java.io.filenotfoundException; import java.io.fileOutputStream; import java.io.ioexception; import java.io.ObjectUnstream; clase saveAndread {public static void main (string [] args) {try {myObject myObject = myObject.getInStance (); FileOutputStream fosref = new FileOutputStream (nuevo archivo ("myObjectFile.txt")); ObjectOutputStream oosref = new ObjectOutputStream (fosref); oosref.writeObject (myObject); oosref.close (); fosref.close (); System.out.println (myObject.hashCode ()); } catch (FileNotFoundException e) {E.PrintStackTrace (); } catch (ioException e) {E.PrintStackTrace (); } FileInputStream FisRef; intente {fisRef = new FileInputStream (nuevo archivo ("myObjectFile.txt")); ObjectInputStream iosref = new ObjectInputStream (fisref); MyObject myObject = (myObject) iosref.readObject (); eosref.close (); fisref.close (); System.out.println (myObject.hashCode ()); } catch (FileNotFoundException e) {E.PrintStackTrace (); } catch (ioException e) {E.PrintStackTrace (); } catch (ClassNotFoundException e) {E.PrintStackTrace (); }}}resultado
970928725
1099149023
Dos hashcodes diferentes demuestran que no son el mismo objeto. Solución, agregue el siguiente código
MyObject protegido readResolve () {System.out.println ("El método readresolve se llamó!"); regresar myobjecthandler.myobject; }Llamado durante la deserialización, puede obtener el mismo objeto
System.out.println (myObject.readResolve (). HashCode ());
resultado
1255301379
¡Se llamó al método Readresolve!
1255301379
El mismo húsico demuestra que se obtiene el mismo objeto
5. Use bloques de código estático para implementar un caso único
El código en el bloque de código estático ya se ejecuta cuando se usa la clase, por lo que la característica del código estático se puede usar para implementar el modo de beneficio simple.
Clase myobject
paquete com.weishiyao.learn.day8.singleton.ep6; clase pública myobject {private static myobject instance = null; private myObject () {super (); } static {instance = new MyObject (); } public static myObject getInstance () {Instance de retorno; }} Clase de hilo
paquete com.weishiyao.learn.day8.singleton.ep6; public class myThread extiende el hilo {@Override public void run () {for (int i = 0; i <5; i ++) {system.out.println (myObject.getInstance (). Hashcode ()); }}} Clase de ejecución
paquete com.weishiyao.learn.day8.singleton.ep6; public class run {public static void main (string [] args) {mythread t1 = new mythread (); MyThread t2 = new MyThread (); Mythread t3 = new MyThread (); Mythread t4 = new MyThread (); Mythread t5 = new MyThread (); t1.start (); t2.start (); t3.start (); t4.Start (); t5.Start (); }}Resultados de ejecución:
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
El patrón Singleton seguro a hilo se obtiene con éxito a través de la característica de solo ejecutar bloques de código estático una vez.
6. Use tipos de datos de enum enum para implementar el modo singleton
Las características de Enum enum y bloques de código estático son similares. Al usar enums, el constructor se llamará automáticamente y también se puede usar para implementar el modo singleton.
Clase myobject
paquete com.weishiyao.learn.day8.singleton.ep7; import java.sql.connection; import java.sql.drivermanager; import java.sql.sqlexception; public enum myobject {ConnectionFactory; conexión de conexión privada; private myObject () {try {system.out.println ("se llamó la construcción de myObject"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? UseUnicode = true & caracterSencoding = utf-8"; Name de cadena = "root"; String Password = "111111"; String Drivername = "com.mysql.jdbc.driver"; Class.forname (Drivername); conexión = drivermanager.getConnection (url, nombre, contraseña); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } Catch (Sqlexception e) {E.PrintStackTrace (); }} Public Connection getConnection () {return Connection; }} Clase de hilo
paquete com.weishiyao.learn.day8.singleton.ep7; public class myThread extiende hilo {@Override public void run () {for (int i = 0; i <5; i ++) {system.out.println (myObject.connectionFactory.getConnection (). Hashcode ()); }}} Clase de ejecución
paquete com.weishiyao.learn.day8.singleton.ep7; public class run {public static void main (string [] args) {mythread t1 = new myThread (); MyThread t2 = new MyThread (); Mythread t3 = new MyThread (); Mythread t4 = new MyThread (); Mythread t5 = new MyThread (); t1.start (); t2.start (); t3.start (); t4.Start (); t5.Start (); }}Resultados de ejecución
Llamado la construcción myobject
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
El método de escritura anterior expone la clase de enumeración, que viola el "principio de responsabilidad única". Puede usar una clase para envolver la enumeración.
paquete com.weishiyao.learn.day8.singleton.ep8; import java.sql.connection; import java.sql.drivermanager; import java.sql.sqlexception; clase pública myobject {public enum myenumsingleton {ConnectionFactory; conexión de conexión privada; privado myenumsingleton () {try {System.out.println ("La construcción de myObject se llamó"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? UseUnicode = true & caracterSencoding = utf-8"; Name de cadena = "root"; String Password = "111111"; String Drivername = "com.mysql.jdbc.driver"; Class.forname (Drivername); conexión = drivermanager.getConnection (url, nombre, contraseña); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } Catch (Sqlexception e) {E.PrintStackTrace (); }} Public Connection getConnection () {return Connection; }} Public Static Connection getConnection () {return myEnumsingleton.ConnectionFactory.getConnection (); }} Cambiar el código de hilo
paquete com.weishiyao.learn.day8.singleton.ep8; public class myThread extiende el hilo {@Override public void run () {for (int i = 0; i <5; i ++) {system.out.println (myObject.getConnection (). Hashcode ()); }}} Como resultado, la construcción myobject se llama
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
Lo anterior resume varias situaciones y soluciones encontradas al combinar el modo de interés único con múltiples subprocesos, de modo que se pueda revisar cuando se usa más adelante.