• 单例模式(Singleton Pattern)


    单例模式使用场景很多:session,上下文,数据库连接池,全局配置文件等。

    单例模式的写法也有很多种:

    1.饿汉式 : 加载类的时候,就创建对象。线程安全。但有的时候不一定用得着,可能造成内存浪费。

    package stu.design.singleton.hungry;
    
    public class HungrySingleton {
    
        private static final HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton() {
        }
    
        public static HungrySingleton getInstance() {
            return hungrySingleton;
        }
    }
    View Code

    1.2 静态饿汉式:在类中的静态属性中创建类。

    package stu.design.singleton.hungry;
    
    public class HungryStaticSingleton {
    
        private static final HungryStaticSingleton hungrySingleton;
    
        static {
            hungrySingleton = new HungryStaticSingleton();
        }
    
        private HungryStaticSingleton() {
        }
    
        public static HungryStaticSingleton getInstance() {
            return hungrySingleton;
        }
    }
    View Code

    2.懒汉式: 第一次调用getInstance()方法的时候再创建。 容易造成线程安全问题。

    package stu.design.singleton.lazy;
    
    public class LazySimpleSingleton {
    
        private static LazySimpleSingleton lazy = null;
    
        private LazySimpleSingleton() {
        }
    
        public synchronized static LazySimpleSingleton getInstance() {
            if (null == lazy) {
                lazy = new LazySimpleSingleton();
            }
            return lazy;
        }
    }
    View Code

    2.2 双重检测懒汉式:懒汉式中,使用synchronized 锁加到方法上,影响性能。 可以加锁到执行代码间。

    package stu.design.singleton.lazy;
    
    public class LazyDoubleCheckSingleton {
    
        private volatile static LazyDoubleCheckSingleton lazy = null;
    
        private LazyDoubleCheckSingleton() {
        }
    
        public static LazyDoubleCheckSingleton getInstance() {
            if (null == lazy) {
                synchronized (LazyDoubleCheckSingleton.class) {
                    if (null == lazy) {
                        lazy = new LazyDoubleCheckSingleton();
                    }
                }
            }
            return lazy;
        }
    }
    View Code

    2.3 内部静态类的单例模式: 内部静态类在类加载的时候,JVM底层实现了实例化。其可能会被序列化破坏,需实现 Serializable 的 readResolve()方法

    package stu.design.singleton.lazy;
    
    import java.io.Serializable;
    
    // static inner class
    public class LazyInnerClassSingleton implements Serializable {
    
        // 防止反射破坏单例模式
        private LazyInnerClassSingleton() {
            if (null != LazyHolder.lazy) {
                throw new RuntimeException("not allow many instance");
            }
        }
    
        public static final LazyInnerClassSingleton getInstance() {
            return LazyHolder.lazy;
        }
    
        private static class LazyHolder {
            private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();
        }
    
        // 防止序列化破坏单例模式
        private Object readResolve(){
            return LazyHolder.lazy;
        }
    }
    View Code

    3.枚举实现: 枚举的优势在于JVM底层避免了枚举类型被反射,序列化破坏其单例性。

    package stu.design.singleton.register;
    
    public enum EnumSingleton {
        INSTANCE;
    
        // 实例化的对象
        private Object data;
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    
        public static EnumSingleton getInstance() {
            return INSTANCE;
        }
    }
    View Code

    3.2 容器实现: 容器中线程不安全,容器使用个的是每个线程作为主键。 所以是每个线程是安全,但线程间不是同一单例。

    package stu.design.singleton.register;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class ContainerSingleton {
        
        private ContainerSingleton() {
        }
    
        private static Map<String, Object> ioc = new ConcurrentHashMap<>();
    
        public static Object getBean(String className) {
            synchronized (ioc) {
                if (!ioc.containsKey(className)) {
                    Object obj = null;
                    try {
                        obj = Class.forName(className).newInstance();
                        ioc.put(className, obj);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return obj;
                }
                return ioc.get(className);
            }
        }
    }
    View Code

    4.伪线程安全实现:每个线程的单例是安全的,但线程与线程间的不是安全的。

    package stu.design.singleton.threadlocal;
    
    /**
     * 伪线程安全
     * 使用threadLocal,多数据源动态切换
     * data source route
     */
    public class ThreadLocalSingleton {
    
        private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>() {
            @Override
            protected ThreadLocalSingleton initialValue() {
                return new ThreadLocalSingleton();
            }
        };
    
        public static ThreadLocalSingleton getInstance() {
            return threadLocalInstance.get();
        }
    }
    View Code

    推荐使用枚举实现。

    欢迎指正。

  • 相关阅读:
    c++经典书籍介绍
    jpeg软解码实现介绍
    视频编解码类型调查——抖音客户端
    微机接口复习
    更改MySQL数据库的密码
    python学习之创建我的第一个Django项目
    关于 V831 linux 调用 gpio 的一些通用操作。
    SpringBoot整合H2内存数据库快速启动测试
    MybatisPlus的各种功能使用笔记综合!
    MybatisPlus的自动填充功能使用!
  • 原文地址:https://www.cnblogs.com/Payne-SeediqBale/p/10958884.html
Copyright © 2020-2023  润新知