• 单列设计模式


    单列中的四种实现方式

    方式一:普通的饿汉式和懒汉式单例模式

    三部曲:

    (1)私有化构造方法
    (2)私有化静态本类对象作为属性
    (3)提供公有静态方法获取本类对象

     1.普通的饿汉式(静态的内部)

    public class Client {
        public static void main(String[] args) {
            Singleton.getInstance();
        }
    
        static class Singleton {
            private static final Singleton instance = new Singleton();
    
            private Singleton(){}
    
            public static Singleton getInstance(){
                return  instance;
            }
    
        }
    }

    2.饿汉式静态代码块单例模式

    //饿汉式静态代码块单例模式
    public class HungryStaticSingleton {
        private static final HungryStaticSingleton instance;
    
        static {
            instance = new HungryStaticSingleton();
        }
    
        private HungryStaticSingleton(){}
    
        public static HungryStaticSingleton getInstance(){
            return  instance;
        }
    }

    3.饿汉式静态代码块单例模式

    /**
     * 优点:执行效率高,性能高,没有任何的锁
     * 缺点:某些情况下,可能会造成内存浪费
     */
    //饿汉式静态代码块单例模式
    public class HungrySingleton {
    
        private static final HungrySingleton instance = new HungrySingleton();
    
        private HungrySingleton(){}
    
        public static HungrySingleton getInstance(){
            return  instance;
        }
    }

    二:懒汉式

    1.懒汉式单例模式在外部需要使用的时候才进行实例化,这种是线程不安全的,如果多个线程同时并发访问,假设多个线程同时都进入到了 if(instance == null){}条件判断里面,那么就会同时创建多个对象。

    /**
     * 优点:节省了内存,线程安全
     * 缺点:性能低
     */
    //懒汉式单例模式在外部需要使用的时候才进行实例化
    public class LazySimpleSingletion {
        //静态块,公共内存区域
        private static LazySimpleSingletion instance;
    
        private LazySimpleSingletion(){}
    
        public synchronized static LazySimpleSingletion getInstance(){
            if(instance == null){
                instance = new LazySimpleSingletion();
            }
            return instance;
        }
    }

    2.单次检查机制(使用类锁),这种也是有缺点的,使用的 synchronized 关键字,严重的影响了性能.

    public class Singleton {
        private static Singleton instance = null;
        public  static Singleton getInstance() {
            synchronized (Singleton.class) {
                if(null == instance) {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    }

    3.利用双重检查机制(DCL) ,保证了线程的安全

    /**
     * 优点:性能高了,线程安全了
     * 缺点:可读性难度加大,不够优雅
     */
    public class LazyDoubleCheckSingleton {
        private volatile static LazyDoubleCheckSingleton instance;
        private LazyDoubleCheckSingleton(){}
    
        public static LazyDoubleCheckSingleton getInstance(){
            //检查是否要阻塞
            if (instance == null) {
                synchronized (LazyDoubleCheckSingleton.class) {
                    //检查是否要重新创建实例
                    if (instance == null) {
                        instance = new LazyDoubleCheckSingleton();
                        //指令重排序的问题
                    }
                }
            }
            return instance;
        }
    }

    4.自认为史上最牛的单例模式的实现方式 (这里有个技术上的高深的点技术基础点,说到底还是技术的基础和本质)----->>>> 利用了Java本身语法特点,内部类默认不加载

    /*
      ClassPath : LazyStaticInnerClassSingleton.class
                  LazyStaticInnerClassSingleton$LazyHolder.class
       优点:写法优雅,利用了Java本身语法特点,性能高,避免了内存浪费,不能被反射破坏
       缺点:不优雅
     */
    //这种形式兼顾饿汉式单例模式的内存浪费问题和synchronized的性能问题
    //完美地屏蔽了这两个缺点
    //自认为史上最牛的单例模式的实现方式
    public class LazyStaticInnerClassSingleton {
        //使用LazyInnerClassGeneral的时候,默认会先初始化内部类
        //如果没使用,则内部类是不加载的
        private LazyStaticInnerClassSingleton(){
            if(LazyHolder.INSTANCE != null){
                throw new RuntimeException("不允许创建多个实例");
            }
        }
        //每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个方法不会被重写、重载
        private static LazyStaticInnerClassSingleton getInstance(){
            //在返回结果以前,一定会先加载内部类
            return LazyHolder.INSTANCE;
        }
    
        //利用了Java本身语法特点,内部类默认不加载
        private static class LazyHolder{
            private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();
        }
    
    }

    5.枚举法

    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;}
    }

     6.序列化一个单列对象

    import java.io.Serializable;
    
    public class SeriableSingleton implements Serializable {
    
    
        //序列化
        //把内存中对象的状态转换为字节码的形式
        //把字节码通过IO输出流,写到磁盘上
        //永久保存下来,持久化
    
        //反序列化
        //将持久化的字节码内容,通过IO输入流读到内存中来
        //转化成一个Java对象
    
    
        public  final static SeriableSingleton INSTANCE = new SeriableSingleton();
        private SeriableSingleton(){}
    
        public static SeriableSingleton getInstance(){
            return INSTANCE;
        }
    
        private Object readResolve(){ return INSTANCE;}
    
    }

    7.手动创建一个单列对象(根据类名来创建)

    public class ContainerSingleton {
    
        private ContainerSingleton(){}
    
        private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();
    
        public static Object getInstance(String className){
            Object instance = null;
            if(!ioc.containsKey(className)){
                try {
                    instance = Class.forName(className).newInstance();
                    ioc.put(className, instance);
                }catch (Exception e){
                    e.printStackTrace();
                }
                return instance;
            }else{
                return ioc.get(className);
            }
        }
    }

    8.ThreadLocal设置单列

    public class ThreadLocalSingleton {
        private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance =
                new ThreadLocal<ThreadLocalSingleton>(){
                    @Override
                    protected ThreadLocalSingleton initialValue() {
                        return new ThreadLocalSingleton();
                    }
                };
    
        private ThreadLocalSingleton(){}
    
        public static ThreadLocalSingleton getInstance(){
            return threadLocaLInstance.get();
        }
    }
  • 相关阅读:
    Flex基础知识
    Java -version与配置的Path环境变量不一致
    Oracle 11g不能导出空表的问题解决(转)
    深入浅出JSONP--解决ajax跨域问题(转)
    Ubuntu 16.04安装docker
    观察者模式 —— java.util.Observable + java.util.Observer 源码学习
    Hashtable的contains() 、containsKey()和containsValue() 区别
    《Java核心技术卷1》拾遗
    openTSDB (rpm)安装 + Grafana 视图
    整合 springboot 和 swagger出问题
  • 原文地址:https://www.cnblogs.com/cb1186512739/p/14264934.html
Copyright © 2020-2023  润新知