设计模式-单例模式

目录

单例模式定义

应用场景

Runtime.java

DefaultSingletonBeanRegistry.java

ReactiveAdapterRegistry.java

Currency.java

实现方式

1、懒汉模式

2、恶汉模式

3、静态内部类

反射打破单例模式情况


单例模式定义

保证一个类只有一个实例,并且提供一个全局访问点

设计模式-单例模式_第1张图片

应用场景

线程池、连接池等情况

Runtime.java

标准的恶汉模式

DefaultSingletonBeanRegistry.java

懒汉模式

ReactiveAdapterRegistry.java

volatile的懒汉模式

Currency.java

带序列化和反序列化

实现方式

1、懒汉模式

  • 线程安全
  • 双重校验
  • 防止指令重排 voilatile
package com.example.demo.designPattern.singleton;

/**
 * @author 10450
 * @description 懒汉模式
 * 并发情况下,有可能
 * @date 2022/9/15 13:58
 */
public class LazySingletonTest {
    public static void main(String[] args){
        new Thread(()->{
            LazySingleton intance = LazySingleton.getSingleton();
            System.out.println(intance);
        }).start();

        new Thread(()->{
            LazySingleton intance = LazySingleton.getSingleton();
            System.out.println(intance);
        }).start();

        new Thread(()->{
            LazySafeSingleton intance = LazySafeSingleton.getSingleton();
            System.out.println(intance);
        }).start();

        new Thread(()->{
            LazySafeSingleton intance = LazySafeSingleton.getSingleton();
            System.out.println(intance);
        }).start();

        new Thread(()->{
            LazyVolatileSingleton intance = LazyVolatileSingleton.getSingleton();
            System.out.println(intance);
        }).start();

        new Thread(()->{
            LazyVolatileSingleton intance = LazyVolatileSingleton.getSingleton();
            System.out.println(intance);
        }).start();
    }
}

/**
 * 多线程不安全
 */
class LazySingleton{
    private static LazySingleton instance;
    private LazySingleton(){
    }
    public static LazySingleton getSingleton(){
        if(instance==null){
            try{
                Thread.sleep(5000);
                instance =  new LazySingleton();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return instance;
    }
}
/**
 * 多线程安全,但是指令重排有问题
 */
class LazySafeSingleton{
    private static LazySafeSingleton instance;
    private LazySafeSingleton(){
    }
    public static LazySafeSingleton getSingleton(){
        if(instance==null){
            synchronized (LazySafeSingleton.class){
                if(instance==null){
                    try{
                        Thread.sleep(5000);
                        instance =  new LazySafeSingleton();
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return instance;
    }
}

/**
 * 防止指令重排
 */
class LazyVolatileSingleton{
    private volatile static LazyVolatileSingleton instance;
    private LazyVolatileSingleton(){
    }
    public static LazyVolatileSingleton getSingleton(){
        if(instance==null){
            synchronized (LazyVolatileSingleton.class){
                if(instance==null){
                    try{
                        Thread.sleep(5000);
                        instance =  new LazyVolatileSingleton();
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return instance;
    }
}



2、恶汉模式

类加载的初始化节点完成实例初始化。本质就是JVM类加载机制,保证实例唯一性。

类加载过程:

  1. 加载二进制字节码数据到内存中,生成对应class数据结构
  2. 连接:a:验证、b:准备(给类的静态成员变量赋默认值),c:解析
  3. 初始化:给类静态变量赋初值
  4. package com.example.demo.designPattern.singleton;
    
    /**
     * @author 10450
     * @description 恶汉模式
     * 类加载的时候完成初始化
     * @date 2022/9/15 14:23
     */
    public class HungrySingletonTest {
        public static void main(String[] args) {
            System.out.println(HungrySingleton.getInstance());
            System.out.println(HungrySingleton.getInstance());
        }
    }
    
    class HungrySingleton{
        private static HungrySingleton  instance = new HungrySingleton();
        private HungrySingleton(){
        }
        public static HungrySingleton getInstance(){
            return instance;
        }
    }

    3、静态内部类

  • 本质上利用类的加载机制保证线程安全
  • 只要在实际使用的时候才会触发累的初始化,也是懒加载的一种
  • package com.example.demo.designPattern.singleton;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    /**
     * @author 10450
     * @description 静态内部类
     * 可以防止通过反射,实现多利
     * @date 2022/9/15 14:28
     */
    public class InnerClassSingletonTest {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            new Thread(()->{
                System.out.println(InnerClassSingleton.getInstance());
            }).start();
    
            new Thread(()->{
                System.out.println(InnerClassSingleton.getInstance());
            }).start();
            
            //利用反射方式创建类对象打破单例模式,实现多利
            Constructor declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();
            InnerClassSingleton instance = InnerClassSingleton.getInstance();
            System.out.println(innerClassSingleton);
            System.out.println(instance);
        }
    }
    
    class InnerClassSingleton{
        private static class InnerClassSingletonHolder{
            private static InnerClassSingleton instance = new InnerClassSingleton();
        }
        private InnerClassSingleton(){
        }
        public static InnerClassSingleton getInstance(){
            try {
                System.out.println(1);
                Thread.sleep(8000);
                System.out.println(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return InnerClassSingletonHolder.instance;
        }
    }
    

    反射打破单例模式情况

通过反射方式创建类,可以打破单例模式,实现多例效果,

【恶汉模式】、【内部类模式】可以判断防止多例

package com.example.demo.designPattern.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author 10450
 * @description 反射攻击
 * @date 2022/9/15 15:03
 */
public class InnerClassReflexSingletonTest {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //单例保护防止多利情况下:
        Constructor declaredConstructor = InnerClassProtectSingleton.class.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        InnerClassProtectSingleton innerClassSingleton = declaredConstructor.newInstance();
        InnerClassProtectSingleton instance = InnerClassProtectSingleton.getInstance();
        System.out.println(innerClassSingleton);
        System.out.println(instance);
    }
}

/**
 * 防止多例
 */
class InnerClassProtectSingleton {
    private static class InnerClassSingletonHolder {
        private static InnerClassProtectSingleton instance = new InnerClassProtectSingleton();
    }

    private InnerClassProtectSingleton() {
        //添加校验,抛异常
        if (InnerClassSingletonHolder.instance != null) {
            throw new RuntimeException("单例模式,不运行重复创建");
        }
    }

    public static InnerClassProtectSingleton getInstance() {
        return InnerClassProtectSingleton.InnerClassSingletonHolder.instance;
    }
}

你可能感兴趣的