设计模式之美学习-创建型-单例模式(十五)

说明

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

饿汉式

在类加载的时候就创建

复制代码
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();
    }
}
复制代码

 

posted @   意犹未尽  阅读(264)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示