浅谈设计模式——单例模式

目录

什么是单例

使用场景

实现方法

饿汉式(静态常量)

饿汉式(静态代码块)

懒汉式 (内部类)

懒汉式(双重检查锁)

饿汉式(枚举类)

总结:


什么是单例

官方定义: 单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点——”通常我们可以让一个全局变量使得一个对象访问 ,但它不能防止你实例化多个对象 。 一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。[DP]“

众所周知在java中 , 对象的实例最开始会被分配到堆区中的新生代区中 ,而在达到一定条件后,对象会被转移到老年代中。
单例模式就是在对象第一次实例化的时候在堆区中开辟空间,并让栈区中的引用指向对象所在对堆区地址,而在后面的实例化中 , 都不会生成新的对象实例 ,更多的只是让其他栈区引用指向原先的对象实例地址——(对象实例自始至终只有一个,且如果该对象一直可达的话,后续会被分配到老年代中)。

使用场景

单例模式应该是开发种使用较多的一种设计模式,其具备多种使用场景。

一、windows任务管理器 , 每次我们尝试使用 Ctrl+Shift+Esc 的时候 , 可以打开多个任务管理器窗口嘛?

二、网站的全局计数器 , 为保证同步,需要在统一时间统计数据 , 采用单例模式,保证计数器全局唯一 , 从而达到同步技术的效果。

三、类似于第一条,对于一个窗口或组件,始终在同一时间只打开一个。要么打开、要么关闭。

四、开发中的Web配置文件,例如:Vue的main.js , SSM整合框架中的Pom等……

……

实现方法

单例模式实现分为 饿汉式懒汉式

饿汉式(静态常量)

public class SingleTon {
    private SingleTon(){}
    private final static SingleTon Instance = new SingleTon();
    public static SingleTon getInstance() {
        return Instance;
    }
}

Instance  静态变量指向类实例 ,意味着在类加载的时候,就会进行实例化 ,并指向该实例地址

这也是饿汉式的由来—— 类在加载的时候就实例化,而非用户自己去实例化。

饿汉式(静态代码块)

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

static {} 代码块类似于静态变量 , 在java中 , 类在被加载的时候 ,static代码块有且仅有一次被执行。

懒汉式 (内部类)

public class SingleTonTest2 {
//    private static volatile SingleTonTest2 instance;
    private SingleTonTest2() {}
    public static class SingleTonInstance {
        private static final SingleTonTest2 INSTANCE = new SingleTonTest2();
    }
    public static SingleTonTest2 getInstance(){
        return SingleTonInstance.INSTANCE;
    }
}

外部类在加载时并不会主动去加载内部类 , 需要用户主动去调用内部类的类方法、类属性或者实例化内部类!!! 

懒汉式(双重检查锁)

public class SingleTonTest {
    private SingleTonTest(){}
    private static volatile SingleTonTest instace;
    public static SingleTonTest getInstance() {
        if(instace == null) {
            synchronized (SingleTonTest.class) {
                if(instace == null) {
                    instace = new SingleTonTest();
                }
            }
        }
        return instace;
    }
}

第一个 if 判断 , 用来判断该类是否已经实例化 。(多线程下,会有线程安全问题)。

于是 , 在if 代码块中 添加 sync 重量级锁保证同步线程安全。注 : sync锁的是整个类,而不是实例 , 具体细节需要读者学习 java  JUC相关知识 , 在这里就不一一详谈了。 

至于在同步块中的 第二个 if 判断 , 是为了再次确实该类是否已经被初始化 , 从而决定是否实例化还是退出同步。注 : 在该同步块中 , 可能会出现指令重排序问题 ——在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序 , 这时就需要使用 volatile关键修饰 instance , 保证该属性的可见性与有序性 ,具体可参考 JAVA JUC 相关知识点。

饿汉式(枚举类)

enum Singleton {
    INSTANCE;
    dosomething...
}

最为简洁高效的方法 。

优点 : 可以保证线程安全,且不会被反射和序列化 破坏单列。

总结:

1.  实现方式中 , 饿汉式的两种方法均不会产生线程安全问题 。但除了枚举类实现,以上几种均可以通过反射和序列化破坏单例。

2. 为什么静态内部类线程安全?

答: JVM保证对于每一个类或接口C,都有一个唯一的初始化锁LC与之对应;保证一个类的类构造器在多线程环境中被正确的加锁、同步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值