Patrón de diseño_patrón singleton (singleton)

Patrón de diseño_patrón singleton (singleton)

Modo singleton: solo se puede crear una instancia y una instancia es suficiente para el negocio de desarrollo. En este caso, se recomienda utilizar el modo singleton.
Tales como: clase de herramienta, clase de recurso.

1. Cómo escribir el modo singleton
El modo singleton incluye hombre perezoso, hombre hambriento, enumeración, clase interna estática y bloqueo de doble verificación.
Aquí solo escribo sobre dos de uso común: hombre hambriento y clase interna estática. Los que lo acompañan se compararán con otros, pero ciertamente no serán completos.
Este método
evita problemas de sincronización multiproceso basado en el mecanismo del cargador de clases. Sin embargo, se crea una instancia de la instancia cuando se carga la clase. En el modo singleton, la mayoría de los métodos llaman al método getInstance. En este momento, la instancia inicializada obviamente no alcanzar el efecto de carga diferida (carga diferida). Esto es adecuado para situaciones en las que es necesario cargar la clase desde el principio.

public class Car {
    private static final Car car = new Car();

    private Car(){}

    public static  Car getInstance(){
        return car;
    }

    public void driveCar(int index){
        System.out.println("驾驶员已经启动"+index+"汽车");
    }
}

Para comparar, puede observar el método de escritura de clases internas estáticas. Este método de
clases internas estáticas
también utiliza el mecanismo de carga de clases para garantizar que solo haya un hilo al inicializar la instancia. Es diferente del método Hungry (un método muy sutil). diferencia): método hambriento El método es que mientras la clase Singleton esté cargada, se creará una instancia de la instancia (no se logra el efecto de carga diferida). En este método, la clase Singleton se carga y la instancia no necesariamente se inicializa . Debido a que la clase SingletonHolder no se usa activamente, la clase SingletonHolder solo se cargará explícitamente llamando al método getInstance para crear una instancia de la instancia. Imagínese si crear una instancia consume recursos y quiero que se cargue lentamente. Por otro lado, no quiero crear una instancia cuando se carga la clase Singleton, porque no puedo asegurar que la clase Singleton pueda usarse activamente en otros lugares.está cargado, entonces obviamente no es apropiado crear una instancia de la instancia en este momento. En este momento, este método parece muy razonable en comparación con el método del hombre hambriento.

public class CarStaticClass {
    private static class CarStaticClassHolder{
        private static CarStaticClass car = new CarStaticClass();
    }
    private CarStaticClass(){};

    public static final CarStaticClass getInstance(){
        return CarStaticClassHolder.car;
    }
}

Las dos anteriores son las formas de escritura más utilizadas. Aquí estoy escribiendo sobre el camino del hombre perezoso y algunas cosas a las que prestar atención en el camino del hombre perezoso.
Método perezoso (inseguro para subprocesos)
: generalmente, se crearán varios objetos cuando varios subprocesos lo llamen al mismo tiempo. Obviamente, no se logra el propósito de un singleton. Porque Car está vacío cuando lo llama un hilo (A). El auto también está vacío cuando lo llama otro hilo (B). Luego se crearán dos objetos Car al mismo tiempo. Es decir, se devuelven dos objetos Car. Por lo tanto, esta forma de escribir generalmente no logra el propósito de Singleton. Pero obviamente es una carga diferida, pero solo se puede pasar debido a la inseguridad del hilo.

/*实例化类*/
public class Car {
    
    
    private static Car car;

    private Car(){}

    public static synchronized Car getInstance(){
        if(car == null){
            System.out.println("创建Car对象");
            car = new Car();
        }
        return car;
    }

    public void driveCar(int index){
        System.out.println("驾驶员已经启动汽车");
    }
}

/*========================================*/
/*调用类这里可以看出多线程的方式调用。代码都比较简单就没写注释了*/
public class Client extends Thread{
    
    

    public void run(){
        for(int i =0 ;i<5; i++){
            Car car = Car.getInstance();
            car.driveCar(i);
        }
    }


    public static void main(String args[]){
        Client client1 = new Client();
        Client client2 = new Client();
        client1.start();
        client2.start();
    }
}

/*========================================*/
/*运行结果*/
创建了Car
创建了Car
驾驶员已经启动0汽车
驾驶员已经启动0汽车
驾驶员已经启动1汽车
驾驶员已经启动2汽车
驾驶员已经启动3汽车
驾驶员已经启动4汽车
驾驶员已经启动1汽车
驾驶员已经启动2汽车
驾驶员已经启动3汽车
驾驶员已经启动4汽车

Lazy (seguro para subprocesos)
tiene pocos cambios de código en comparación con subprocesos inseguros y agrega un bloqueo. También tiene el efecto de carga diferida. Pero lo que te digo es que este método es muy ineficiente.

public class Car {
    private static final Car car = new Car();

    private Car(){}

    public static synchronized  Car getInstance(){
        return car;
    }

    public void driveCar(int index){
        System.out.println("驾驶员已经启动"+index+"汽车");
    }
}

En cuanto a las otras formas. Parece que rara vez se ve en el trabajo real. A continuación se ofrecen algunas instrucciones sencillas. El método de enumeración es relativamente raro y creo que su función principal es evitar que la deserialización vuelva a crear nuevos objetos. Si existe un requisito de creación de instancias, se puede implementar la interfaz de serialización.
No creo que el método de bloqueo de doble verificación sea necesario. Si no es una ocasión específica, realmente no es necesario utilizar el bloqueo de doble verificación. Para obtener más información, consulte
2. Explicación de
por qué el modo singleton puede convertirse en singleton. Puede que no sea muy diferente si el código es normal. Queridos amigos, miren el método de construcción del patrón singleton: su método de construcción no tiene parámetros y es privado. Esto asegurará que no se puedan crear objetos externos a través de nuevos. Solo se puede construir mediante el método getInstance. En este método está el objeto devuelto, que ha sido inicializado. Y es final y estático. De esta manera no se generarán nuevos objetos.
En cuanto a si utilizar Hungry Man o clases internas estáticas, depende del escenario. Generalmente, se usa Hungry a menos que se usen explícitamente clases internas estáticas. Asegúrese de garantizar la seguridad del hilo cuando lo utilice.

Supongo que te gusta

Origin blog.csdn.net/my_God_sky/article/details/52201222
Recomendado
Clasificación