zoukankan      html  css  js  c++  java
  • 设计模式 单例模式

    • 优点:
    1. 只有一个实例,减少内存开支,减少创建销毁和初始化的性能开销
    2. 可以避免资源的多重占用,一种资源操作只有一个实例进行操作
    3. 提供全局访问点,优化和共享资源访问
    • 缺点:
    1. 单例模式要求自行实例化,并提供单一实例,因此单例对象的扩展只能对其自身进行修改
    2. 单例模式与开闭原则、单一职责原则冲突

    饿汉式单例

    // 饿汉式单例,类文件初始化过程中完成单例实例化
    public class HungrySingleton {
        private static final HungrySingleton instance = new HungrySingleton();
    
        // static {
        //     instance = new HungryStaticSingleton();
        // }
        
        private HungrySingleton(){}
    
        public static HungrySingleton getInstance(){return instance;}
    }
    

    懒汉式单例

    双重校验锁

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

    volatile 防止指令重排序:使INVOKESPECIAL(初始化指令) 先于 PUTSTATIC(引用赋值指令)

     // t = new Test();
     // NEW指令,创建指定类型的对象实例、对其进行默认初始化,并且将指向该实例的一个引用压入操作数栈顶;
     NEW Test
     // invokespecial会消耗掉操作数栈顶的引用作为传给构造器的“this”参数,所以如果我们希望在invokespecial调用后在操作数栈顶还维持有一个指向新建对象的引用,则使用DUP指令复制操作栈顶数据并入栈
     DUP
     // 调用<init>方法,<init>方法为实例方法,需消耗栈顶的一个对象引用
     INVOKESPECIAL Test.<init> ()V
     // 将引用赋值给静态变量Test.t;
     PUTSTATIC Test.t : LTest;
    

    静态内部类

    /*
     * 内部静态类实现懒汉式单例
     *
     * 由于java类的加载机制,在加载LaztStaticInnerClassSingleton时,并不会加载LazyHolder类
     * 只有当调用getInstance方法时,才会对LazyHolder进行加载,从而实现懒加载
     */
    public class LazyStaticInnerClassSingleton {
    
        private LazyStaticInnerClassSingleton(){}
    
        public static LazyStaticInnerClassSingleton getInstance(){
            return LazyHolder.instance;
        }
    
        private static class LazyHolder{
            private static final LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
        }
    }
    

    枚举式单例

    // 枚举式单例(饿汉) - 可避免反射破坏 - 枚举类型不允许反射创建实例
    public enum EnumSingleton {
        instance;
    
        // 其实这段方法并没有太大意义,不过习惯使用getInstance表示单例,直接用EnumSingleton.instance也可。
        public static EnumSingleton getInstance(){return instance;}
    
        // 以下为应用属性和代码
        private int index = 0;
    
        public void print(){
            System.out.println(index);
        }
    }
    
    // 枚举类的实际实现:
      public final static enum Ltop/kiqi/design/pattern/singleton/hungry/EnumSingleton; instance
    // synthetic 标记,由编译器生成的属性/方法/类
      private final static synthetic [Ltop/kiqi/design/pattern/singleton/hungry/EnumSingleton; $VALUES
    
      static{
          instance = new EnumSingleton("instance",0);
          $VALUES = new EnumSingleton[]{instance};
      }
    

    容器式单例(IOC)

    public class ContainerSingleton{
        private static ConcurrentHashMap<String,Object> ioc = new ConcurrentHashMap<>();
    
        private ContainerSingleton(){
            throw new RuntimeException("非法访问!");
        }
    
        // 方法一: 双重校验锁
        public static Object getInstance(String className){
            if(!ioc.contains(className)){
                synchronized (ContainerSingleton.class){
                    if(!ioc.contains(className)){
                        try{
                            Object instance = Class.forName(className).newInstance();
                            ioc.put(className,instance);
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }
            return ioc.get(className);
        }
    
        // 方法二: 利用ConcurrentHashMap的putIfAbsent
        public static Object getInstance(String className){
            if(!ioc.contains(className)){
                try {
                    ioc.putIfAbsent(className, Class.forName(className).newInstance());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            return ioc.get(className);
        }
    }
    

    线程私有式单例

    // 线程级单例 - 使用ThreadLocal为每个线程私有维护一份实例对象
    public class ThreadLocalSingleton {
        private static ThreadLocal<ThreadLocalSingleton> threadLocalSingleton = ThreadLocal.withInitial(ThreadLocalSingleton::new);
    
        private ThreadLocalSingleton(){}
    
        public static ThreadLocalSingleton getInstance(){
            return threadLocalSingleton.get();
        }
    }
    

    避免破坏单例

    避免反射破坏单例

     // 构造方法中添加判断
        private Singleton(){
            if(instance != null){
                throw new RuntimeException("非法访问!");
            }
        }
    

    避免反序列化破坏单例:

     // 实现方法 - 当调用java反序列化方法(ObjectInputStream.readObject())时,会判断该方法,如果存在,则使用该方法的返回值。
     public Object readResolve(){
        return instance;
     };
    
  • 相关阅读:
    50个jQuery 插件可将你的网站带到另外一个高度
    Web 开发中 20 个很有用的 CSS 库
    【算法】1、约瑟夫环
    智造微博
    银河系中央超大黑洞可能是个虫洞 其连接着两个不同的时空。
    创意文案:我害怕阅读的人
    解决Oracle ORA-00984: column not allowed here
    舌尖上的程序员
    技术贴 本地代码与svn关联教程 svn upgrade问题解决
    Aimp3的播放列表 按评分排序 落雨
  • 原文地址:https://www.cnblogs.com/kiqi/p/14007606.html
Copyright © 2011-2022 走看看