zoukankan      html  css  js  c++  java
  • 设计模式之美学习-创建型-单例模式(十五)

    说明

    从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。除此之外,我们还可以使用单例解决资源访问冲突的问题。

    饿汉式

    在类加载的时候就创建

    public class IdGenerator {
        private AtomicLong id = new AtomicLong(0);
        //2.类加载的时候就初始化
        private static final IdGenerator instance = new IdGenerator();
        //1.构造函数私有化
        private IdGenerator() {
        }
        //3.提供一个公共的静态方法
        public static IdGenerator getInstance() {
            return instance;
        }
        public long getId() {
            return id.incrementAndGet();
        }
    }

    懒汉式

    普通版本

    public class IdGenerator {
        private AtomicLong id = new AtomicLong(0);
        private static IdGenerator instance;
        //构造哈数私有化
        private IdGenerator() {
        }
        //加锁 避免并发的时候多次创建
        public static synchronized IdGenerator getInstance() {
            if (instance == null) {
                instance = new IdGenerator();
            }
            return instance;
        }
        public long getId() {
            return id.incrementAndGet();
        }
    }

    缺点:方法加了同步锁避免多线程并发 重复创建,但是当初始化后每次获取都会获取锁,性能不好

    双重检测

    public class IdGenerator {
        private AtomicLong id = new AtomicLong(0);
        private static volatile IdGenerator instance;
        //构造函数私有化
        private IdGenerator() {}
        public static IdGenerator getInstance() {
            if (instance == null) {
                synchronized(IdGenerator.class) { // 此处为类级别的锁
                    //二次判断是为了防止多线程在同步锁等待 第一个释放后 其余进入锁 会重复创建
                    if (instance == null) {
                        instance = new IdGenerator();
                    }
                }
            }
            return instance;
        }
        public long getId() {
            return id.incrementAndGet();
        }
    }

    静态内部类

    public class IdGenerator {
        private AtomicLong id = new AtomicLong(0);
        //构造函数私有化
        private IdGenerator() {}
    
        //加载IdGenerator时SingleonHoldre并不会加载
        private static class SingletonHolder{
            private static final IdGenerator instance = new IdGenerator();
        }
    
        //调用get方你发触发holder加载 
        public static IdGenerator getInstance() {
            return SingletonHolder.instance;
        }
    
        public long getId() {
            return id.incrementAndGet();
        }
    }

    防止单列模式被破坏 

    1、防止反射破环(虽然构造方法已私有化,但通过反射机制使用newInstance()方法构造方法也是可以被调用):

    • 首先定义一个全局变量开关isFristCreate默认为开启状态
    • 当第一次加载时将其状态在更改为关闭状态

    2、防止克隆破环

    • 重写clone(),直接返回单例对象

    3、防止序列化破环

    • 添加readResolve(),返回Object对象
    public class Singleton  implements Serializable,Cloneable{
        private static final long serialVersionUID = 6125990676610180062L;
        private static Singleton singleton;
        private static boolean isFristCreate = true;//默认是第一次创建
        
        private Singleton(){
                if (isFristCreate) {
                    synchronized (Singleton.class) {            if (isFristCreate) {              isFristCreate = false;            }
                    }
                }else{
                    throw new RuntimeException("已然被实例化一次,不能在实例化");
                }
        }
        public void doAction(){
            //TODO 实现你需要做的事
        }
        public  static Singleton getInstance(){
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
        @Override
        protected Singleton clone() throws CloneNotSupportedException {
            return singleton;
        }
        private Object readResolve() {
            return singleton;
        }
    }

    摘自:https://www.cnblogs.com/call-me-pengye/p/11169051.html

    使用枚举

    /**
     * 使用   IdGenerator.instance.getId();
     */
    public enum  IdGenerator {
        instance;
        private AtomicLong id = new AtomicLong(0);
    
        public long getId() {
            return id.incrementAndGet();
        }
    }
  • 相关阅读:
    windows下面编译redis5.0.5
    在ASP.NET Core 2.x中获取客户端IP地址
    https网站访问第三方https网站时候报错: The request was aborted:Could not create SSL/TLS secure channel.
    大量日志Login failed for user 'sa'. 原因: 密码与所提供的登录名不匹配。 [客户端: x.x.x.x] 导致Sql Server 的ErrorLog文件过大几十G
    一次清除SQL SERVER错误日志(ErrorLog)的体会!
    notepad++正则抽取所有符合条件的字符串
    Android编译执行envsetup.sh,产生工具命令m、mm、mmm、mmma、tapas 、croot、cgrep、jgrep、 resgrep、godir
    全志Tina_dolphin播放音视频裸流(h264,pcm)验证
    全志Linux Tina编译demoOmxVdec错误
    linux epoll学习
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12565861.html
Copyright © 2011-2022 走看看