Bloqueo controlado doble en Singleton

aquí está mi clase personalizada para el patrón Singleton. en este código, utilizo el locking con doble verificación como se muestra a continuación. A medida que leo muchas publicaciones sobre alguna fuente, dicen que la verificación doble es útil porque evita que dos hilos simultáneos se ejecuten al mismo tiempo y que formen dos objetos diferentes.

public class DoubleCheckLocking { public static class SearchBox { private static volatile SearchBox searchBox; // private constructor private SearchBox() {} // static method to get instance public static SearchBox getInstance() { if (searchBox == null) { // first time lock synchronized (SearchBox.class) { if (searchBox == null) { // second time lock searchBox = new SearchBox(); } } } return searchBox; } } 

Todavía no entiendo mucho el código anterior. ¿Cuál es el problema, si dos hilos juntos ejecutan la misma línea de código cuando la instancia es nula?

 if (searchBox == null) { synchronized (SearchBox.class) { if (searchBox == null) { searchBox = new SearchBox(); } } } 

Cuando eso aparece. ambos hilos verán que el objeto es nulo. entonces ambos se sincronizan. y luego, lo vuelven a comprobar, y todavía lo ven nulo . y crea dos objetos diferentes OOOPS.

Por favor explique por mi ¿Qué he entendido mal?

Gracias 🙂

No, ya que está obteniendo el locking en SearchBox.class , solo un hilo ingresará al bloque sincronizado a la vez. Entonces, el primer hilo entra y luego busca searchBox y lo crea y luego sale del bloque sincronizado, luego el segundo hilo ingresa al bloque y luego descubre que searchBox no es nulo porque el primer hilo ya lo creó para que no cree una nueva instancia de searchBox

El patrón de verificación doble se utiliza para evitar la obtención del locking cada vez que se ejecuta el código; si la llamada no ocurre conjuntamente, la primera condición fallará y la ejecución del código no ejecutará el locking, lo que ahorrará recursos.

Veamos este código:

 1 if (searchBox == null) { 2 synchronized (SearchBox.class) { 3 if (searchBox == null) { 4 searchBox = new SearchBox(); 5 } 6 } 

Tratemos de razonar sobre esto. Digamos que tenemos dos hilos A y B y supongamos que al menos uno de ellos llega a la línea 3 y observa que searchBox == null es true . Dos hilos no pueden estar en la línea 3 al mismo tiempo debido al bloque synchronized . Esta es la clave para entender por qué funciona el locking comprobado. Entonces, debe darse el caso de que A o B synchronized primero synchronized . Sin pérdida de generalidad, di que ese hilo es A Luego, al ver que searchBox == null es verdadero, ingresará el cuerpo de la statement y establecerá searchBox en una nueva instancia de SearchBox . Eventualmente saldrá del bloque synchronized . Ahora será el turno de B de ingresar: recuerde, B fue bloqueado esperando que A salga. Ahora cuando ingrese al bloque, observará searchBox . Pero A habrá dejado simplemente establecer searchBox en un valor no null . Hecho.

Por cierto, en Java, la mejor forma de implementar un singleton es usar un tipo de elemento enum . De Java efectivo :

Si bien este enfoque aún no se ha adoptado ampliamente, un tipo de enumeración de elemento único es la mejor manera de implementar un singleton.

Este locking de doble verificación solo es necesario si le preocupan muchos hilos que llaman al singleton simultáneamente, o el costo de obtener un candado en general.

Su propósito es evitar la sincronización innecesaria, lo que mantiene su código rápido en un entorno de múltiples subprocesos.

Consulte este enlace para obtener más información.

Si está ejecutando Java 1.5 o una versión superior y usa la palabra clave volatile en su mecanismo de verificación doble bloqueada, funcionará correctamente. A medida que utiliza la palabra clave volatile , su ejemplo no se rompe según el mismo enlace anterior.

 if (searchBox == null) { //1 synchronized (SearchBox.class) { if (searchBox == null) { //2 searchBox = new SearchBox(); } } } } 
  1. Si ya se creó una instancia, no haga nada, evite bloquear los hilos
  2. El primer hilo que ha adquirido el locking comprueba y ve que no existe tal objeto y lo crea. Libera el locking y el segundo puede hacer lo mismo: tiene que verificar si el objeto existe porque el primero puede haberlo creado.

Así que, básicamente, el if externo se usa para evitar lockings redundantes: permite que todos los hilos sepan que ya hay un objeto y que no necesitan bloquear / hacer nada. Y el if interno se usa para permitir que un hilo concurrente sepa si otro ya ha creado el objeto o no.