如何创建一个完美的单例模式,你会么?

简介: 今天,正式介绍一下Java极客技术知识星球SpringBoot 精髓之 SpringBoot-starterSpring 源码学习(八) AOP 使用和实现原理Java:前程似锦的 NIO 2.0java中List元素移除元素的那些坑

java设计模式之单例模式


单例模式的特点

1.单例类只能有一个构造函数,并且是私有的2.单例类必须自己创建自己的唯一实例3.单例类必须给所有其他对象提供这一实例。

单例模式的优缺点

1.优点:在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例2.缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

饿汉式单列

1.优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。2.缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅

下面我们来看下饿汉式单列的代码

public class HungrySingleton {
    //私有的构造函数
    private HungrySingleton() { }
    //自己创建自己的实例
    private static final HungrySingleton hungrySingleton = new HungrySingleton();
    //向其他对象提供这一实例
    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }
}

懒汉式单列

懒汉式单列是线程不安全的

下面我们来看下懒汉式单列的代码

public class LazySimpleSingleton {
    //私有的构造函数
    private LazySimpleSingleton() {}
    private static LazySimpleSingleton lazy = null;
    //实例化对象并提供这一实例
    public static LazySimpleSingleton getInstance() {
        if (lazy == null) {
            lazy = new LazySimpleSingleton();
        }
        return lazy;
    }
}

双重检查锁单例

这种单例模式主要解决懒汉式单列的线程不安全的问题,用了synchronized 加锁,所以性能会有所消耗

下面我们来看下双重检查锁单例的代码

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

静态内部类单例

这种单例模式可以说是完美的单例模式了

1.延迟加载(使用的时候才会实例化),避免项目启动内存的消耗2.内部类一定是在方法调用之前初始化,巧妙地避免了线程安全问题

下面我们来看下双重检查锁单例的代码

public class LazyInnerClassSingleton implements Serializable {
    // 私有的构造方法
    private LazyInnerClassSingleton(){}
    // 公有的获取实例方法
    public static final LazyInnerClassSingleton getInstance(){
        return LazyHolder.LAZY;
    }
    // 静态内部类
    private static class LazyHolder{
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }
}

spring里面单例模式的应用场景

spring里面bean的作用域默认是单例的,比如最常见的controller,service,dao这些.但是spring里面的单例bean对象是线程不安全的,因为如果这些对象里面有成员变量的话,在并发访问的时候这些成员变量将会是并发线程中的共享对象,也是影响线程安全的重要因素

这里给出几个方案

1.将bean的作用域改为prototype2.自己保证线程安全3.不要使用成员变量,尽量使用纯方法的类,如:controller,service,dao

总结

本文主要讲了单例模式的特点,优缺点和4种单例模式的创建,但是这4中单例模式真的是完美的单例模式吗?有没有什么方式可以破坏单例?有没有什么方式可以防止单例被破坏?敬请期待单例模式下一期

欢迎加入我们的知识星球,一起成长,交流经验。加入方式,长按下方二维码噢

最后,我想重复一句话:选择和一群优秀的人一起成长,你成长的速度绝对会不一样!

相关文章
|
2月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
88 0
|
2月前
|
设计模式 缓存 安全
【设计模式】单例模式:确保类只有一个实例
【设计模式】单例模式:确保类只有一个实例
33 0
|
2月前
|
C++
C++实现单例模式-多种方式比较
单例模式,面试中经常被问到,但是很多人只会最简单的单例模型,可能连多线程都没考虑到,本文章从最简单的单例,到认为是最佳的单例模式实现方式,单例模式没有什么知识点,直接上源码
60 0
|
9月前
|
设计模式 安全 Java
JAVA设计模式1:单例模式,确保每个类只能有一个实例
JAVA设计模式1:单例模式,确保每个类只能有一个实例
|
9月前
|
设计模式 安全 Java
特殊类设计及单例模式(C++)
特殊类设计及单例模式(C++)
67 1
|
9天前
|
设计模式 安全 Java
Java中的单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点
Java单例模式确保类仅有一个实例,并提供全局访问点。常见实现包括: - 饿汉式:静态初始化,线程安全。 - 懒汉式:延迟初始化,需同步保证线程安全。 - 双重检查锁定:优化懒汉式,减少同步开销。 - 静态内部类:延迟加载,线程安全。 - 枚举:简洁线程安全,不适用于复杂构造。 - 容器实现:如Spring框架,用于依赖注入。选择依据需求,如延迟加载、线程安全和扩展性。
39 10
|
2月前
|
设计模式 安全 Java
Java设计模式—单例模式的实现方式和使用场景
那么为什么要有单例模式呢?这是因为有的对象的创建和销毁开销比较大,比如数据库的连接对象。所以我们就可以使用单例模式来对这些对象进行复用,从而避免频繁创建对象而造成大量的资源开销。
81 1
|
11月前
|
安全 Java 编译器
单例模式的4种实现方式
单例模式的4种实现方式
81 0
|
开发框架 Java .NET
设计模板-单例模式
设计模板-单例模式
41 0
|
设计模式 安全 Java
23种设计模式-创建模式-单例模式(三)
23种设计模式-创建模式-单例模式(三)