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

    一 定义 

      单例模式(Singleton Pattern):是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

      隐藏其所有的构造方法

      属于创建性模式

    二 单例模式的几种实现方式

      (一)饿汉式单例:在单例类首次加载时就创建单例

    public class HungrySingleton {
    
        private static final HungrySingleton hungrySingletonm = new HungrySingleton();
    
        private HungrySingleton(){}
    
        public HungrySingleton getInstance(){
            return hungrySingletonm;
        }
    
    }
    public class HungryStaticSingleton {
    
        private static final HungryStaticSingleton hungrySingletonm;
    
        private HungryStaticSingleton(){}
    
        static {
            hungrySingletonm = new HungryStaticSingleton();
        }
    
        public HungryStaticSingleton getInstance(){
            return hungrySingletonm;
        }
    
    }
    

      上面两种方式没有本质的区别,都是在类加载时就创建类的实例

      优点:执行效率高,性能高,没有任何的锁

      缺点:某种情况下,可能会造成内存浪费

      (二)懒汉式单例:被外部调用时才创建实例

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

      A方式  优点:不是加载类的时候就被创建,可以节约内存空间

            缺点:不是线程安全的,多线程情况下,会产生多个实例

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

      B方式  优点:节约了内存空间,并且是线程安全的

            缺点:性能很低  

    public class LazySingleton {
        private volatile static LazySingleton instance;
        private  LazySingleton(){}
    
        public static LazySingleton getInstance(){
            if(instance == null){    //第一层检查:检查是否阻塞
                synchronized(LazySingleton.class){
                    if(instance == null){  //第二层检查:检查是否要重新创建实例
                        instance = new LazySingleton();    //这有一个指令重排序的问题,上面的变量上加上volatile字段
                    }
                }
            }
            return instance;
        }
    
    }

      C方式  双重检查,比较好的一种写法

         优点:性能提高了,线程安全了

         缺点:可读性不好,不够优雅

    public class StaticInnerClassSingleton {

    private StaticInnerClassSingleton(){
    if(Holder.INSTANCE != null){
    throw new RuntimeException("不允许非法访问");      //防止反射破坏单例
    }
    }

    public static StaticInnerClassSingleton getInstance(){
    return Holder.INSTANCE;
    }

    private static class Holder{
    private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }
    }

      D方式  写法优雅,利用了java本身的语言特性,性能高,避免了内存浪费

    上面的几种写法都会被反射和序列化破坏单例

      (三)注册式单例:将每一个实例都缓存到统一的容器中,使用唯一标示获取实例  

    public enum EnumSingleton {
        INSTANCE;
        
        public static EnumSingleton getInstance(){
            return INSTANCE;
        }
    }

    枚举式单例可避免序列化破坏和反射破坏

    public class ContainerSingleton {
        private ContainerSingleton(){}
        private static Map<String,Object> ioc=new ConcurrentHashMap<String,Object>();
    
        public static Object getBean(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);
            }
        }
    }

    容器式单例适用于创建实例非常多的情况,便于管理。但是,是非线程安全的。

      (四)ThreadLocal单例:保证线程内部的全局唯一,且天生线程安全。严格上说不能算作是一种单例模式,只是保证了每个线程里的实例是一个

    public class ThreadLocalSingleton {
    
        private static final ThreadLocal<ThreadLocalSingleton> threadLocalSIngleton =
                new ThreadLocal<ThreadLocalSingleton>(){
                    @Override
                    protected ThreadLocalSingleton initialValue() {
                        return new ThreadLocalSingleton();
                    }
                };
    
        private ThreadLocalSingleton(){}
    
        public ThreadLocalSingleton getInstance(){
            return threadLocalSIngleton.get();
        }
    
    }

     

    三   学习单例模式的重点

      1. 私有化构造器

      2. 保证线程安全

      3. 延迟加载

      4. 防止序列化和反序列话破坏单例

      5. 防御反射攻击单例

  • 相关阅读:
    Linux中的邮件发送
    Python学习笔记18-发送邮件
    Ansible学习笔记
    eclipse使用maven打包时去掉测试类
    CentOS安装redis
    spring boot 部署
    sprint boot 配置
    spring-boot 学习笔记一
    不要容忍破窗户
    阿里云安装Oracle
  • 原文地址:https://www.cnblogs.com/hyzxx/p/12434180.html
Copyright © 2011-2022 走看看