JAVA设计模式——单例模式

这篇具有很好参考价值的文章主要介绍了JAVA设计模式——单例模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

单例模式是应用最广的设计模式之一,也是程序员最熟悉的一个设计模式,使用单例模式的类必须保证只能有创建一个对象。

今天主要是回顾一下单例模式,主要是想搞懂以下几个问题

为什么要使用单例?
如何实现一个单例?
单例存在哪些问题?
单例对象的作用域的范围
单例模式是如何保证唯一性的

一、为什么要使用单例?🍉

在开发过程中,很多时候一个类我们希望它只创建一个对象,比如:线程池、缓存、网络请求等。当这类对象有多个实例时,程序就可能会出现异常,比如:程序出现异常行为、得到的结果不一致等。

这时候就应该使用单例模式。

单例主要有这两个优点:

1、提供了对唯一实例的受控访问。

2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

二、实现单例的 5 种方式🍉

实现单例模式主要有以下几个关键点:

构造函数设置为 private ,这避免外部通过 new 创建实例;
通过一个静态方法或者枚举返回单例类对象;
考虑对象创建时的线程安全问题,确保单例类的对象有且仅有一个,尤其是在多线程环境下;
确保单例类对象在反序列化时不会重新构建对象。
考虑是否支持延迟加载;
下面是常见的集中单例模式的实现方式

1、饿汉式
在类加载的期间,就已经将 instance 静态实例初始化好了,所以,instance 实例的创建是线程安全的。不过,这样的实现方式不支持延迟加载实例。

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

2、懒汉式

懒汉式相对于饿汉式的优势是支持延迟加载。

public class Singleton {
    private Singleton(){}
    private static Singleton instance;

    public static synchronized Singleton getInstance(){
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

但它的缺点也很明显,getInstance 使用了 synchronize 实现线程同步,导致这个方法的并发很低,每次调用都会频繁的枷锁、释放锁,会导致性能瓶颈。

3、双重检测
饿汉式不能延时加载,懒汉式有性能问题,而双重检测方式既支持延迟加载、又支持高并发的单例实现方式。

当 instance 对象被创建后,再次调用 getInstance 方法不再会进入 synchronize 加锁的代码之中。

它的优点是:资源利用率高,第一次执行 getInstance 时才会被实例化,效率高。缺点是:第一次加载反应稍慢。

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

有时候,面试官会问这种实现方式有什么问题。他们指的就是指令重排序。

instance = new Singleton(); 并不是一个原子操作, 这句代码实际执行了三件事。

1、 给 Singleton 的实例分配内存;

2、调用 Singleton 的构造函数,初始化成员变量;

3、将 instance 的对象指向分配的内存空间。

因为 Java 编译器允许处理器乱序执行,2、3的顺序是无法保证的。如果是 1-3-2 执行的顺序,当执行完 3 、2未执行之前,被切换到 B 线程,此时 instance 已经非空,B 会直接取走 instance,在使用时就会出错。

这就是指令重排。

解决办法也很简单:只需要给 instance 成员变量加上 volatile 关键字,就可以禁止指令重排序。

其实这个问题在高版本的 java 中已经被解决了,解决方式也很简单,就是把对象 new 操作和初始化操作设计为原子操作,就自然能禁止重排序。

4、静态内部类
除了以上方法外,使用 Java 的静态内部类也能够实现。

public class Singleton {
    private Singleton(){}

    private static class Instance {
        private static final Singleton instance = new Singleton();
    } 

    public static Singleton getInstance(){
        return Instance.instance;
    }
}

当第一次加载 Singleton 类时并不会初始化 instance,只有在第一次调用 Singleton 的 getInstance 方法时才会导致 instance 被初始化。

第一次调用 getInstance 方法时会导致虚拟机加载 Instance 类,这种方式不仅能保证线程安全,也能够保证单例对象唯一,同时也延迟了单例的实例化。

5、枚举
枚举是单例最简单的实现方式,这种实现方式通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

public enum Singleton {
    INSTANCE;
}

三、单例存在哪些问题?🍉

1、对 OOP 特性的支持不友好
面向对象的四大特征是:封装、继承、多态。单例对继承、多态特性的支持不友好。

虽然从理论上来讲,单例类也可以被继承、也可以实现多态,但实现起来会非常奇怪。所以,一旦将某个类设计成到单例类,也就意味着放弃了继承和多态这两个面向对象的特性,也就相当于损失了可以应对未来需求变化的扩展性。

2、单例对代码的扩展性不友好
我们知道,单例类只能有一个对象实例。但如果未来改需求了,需要创建两个或多个实例,就需要对代码有比较大的改动。

3、单例不支持有参数的构造函数
单例不支持有参数的构造函数,如果想要传递参数,只能在 getInstance 方法中添加参数,或者定义方法传递参数。

4、针对这些问题,有何替代的解决方案?
为了保证全局唯一,除了使用单例,还可以用静态方法来实现。不过,静态方法这种实现思路,并不能解决之前提到的问题。

实际上,它比单例更加不灵活,比如,它无法支持延迟加载。

目前并没有什么很好的方式来解决。

四、单例对象的作用域的范围🍉

单例模式的类只能创建一个对象,这个对象的作用域是整个 APP 的生命周期,也就是进程中唯一。

当我们打开 APP 后,系统会开启一个进程,并分配给 APP,接着进程会一条一条地执行 APP 文件中包含的代码,比如 当读到 User user = new User(); 这条语句的时候,它就在自己的地址空间中创建一个 user 临时变量和一个 User 对象。

进程之间是不共享地址空间的,如果我们的 APP 开启多个进程,那么每个进程都会分配新的地址空间,单例模式就会失效。。

单例类中对象的唯一性的作用范围是进程内的,在进程间是不唯一的。

五、单例模式是如何保证唯一性的🍉

这里就需要了解JVM 的类加载机制。

虚拟机的类加载是采用双亲委派模型。

它的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(他的搜索范围中,没有找到这个类),子加载器才会去尝试加载。

JAVA设计模式——单例模式,单例模式,java,设计模式
所以,当单例模式的类被实例化后,因为这个类已经加载过了,再次请求加载时,就不会创建新的,而是会找到已经存在的这个类。

本文就到这里,单例模式虽然比较常用,但是它的知识点还是挺多的。文章来源地址https://www.toymoban.com/news/detail-602212.html

到了这里,关于JAVA设计模式——单例模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java设计模式-单例

    单例模式是一种创建型设计模式,它可以保证一个类只有一个实例,并提供全局访问点。单例模式在实际开发中经常使用,可以避免多个实例引起的资源浪费和同步问题。常见的java实现方式有多种。 饿汉式单例模式是指在类加载时就创建了单例对象,因此在调用时不需要再

    2024年01月18日
    浏览(53)
  • 设计模式篇(Java):单例模式

    上一篇:设计模式篇(Java):前言(UML类图、七大原则) 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。 构造器私有化 (防止 new ) 类的内部创建对象 向外暴露一个静

    2024年02月11日
    浏览(60)
  • Java设计模式---单例 工厂 代理模式

    单例模式是设计模式中的一种,属于创建型模式。在软件工程中,单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于那些需要频繁实例化然后引用,且创建新实例的开销较大的类,例如数据库连接池、缓存管理等。 意图 :保证一个类仅有一个实例

    2024年01月24日
    浏览(51)
  • 【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

    🍎 个人博客: 个人主页 🏆 个人专栏: JAVA ⛳️   功不唐捐,玉汝于成 目录 前言 正文 懒汉式(Lazy Initialization): 双重检查锁定(Double-Checked Locking): 结语 我的其他博客 在软件设计中,单例设计模式是一种重要的设计思想,它确保了一个类只有一个实例,并提供了一

    2024年01月15日
    浏览(55)
  • Java与设计模式(4):单例模式

    单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供全局访问点来访问该实例。 在单例模式中,类的构造函数被私有化,从而禁止外部直接实例化该类。通过一个静态方法或静态变量来控制类的实例化过程,并返回同一个实例。 单例模式的特点包括: 单一

    2024年02月12日
    浏览(68)
  • Java设计模式(八)— 单例模式3

    单例模式之静态内部类 单例模式之枚举方式 单例模式之JDK源码分析 Hello,小伙伴们,欢迎来到柚子的博客~让我们一起成长吧o( ̄▽ ̄)ブ 提示:以下是本篇文章正文内容,下面案例可供参考 代码如下(示例): 类被装载的时候,类里面的静态内部类也是会被装载的,而且线

    2024年02月09日
    浏览(76)
  • java设计模式-单例模式(Singleton)

    单例模式(Singleton)就是一个类只能有一个实例,自行实例化,并向系统提供这一实例,这个类就是单例类。单例模式的特点: 一个类只能有一个实例; 单例类自己实例化; 单例类给其它对象提供这个单一实例。 资源管理类经常被设计为单例模式,例如管理属性文件的类。

    2024年02月15日
    浏览(38)
  • Java设计模式之单例模式

    定义:保证一个类仅有一个实例,并提供一个全局访问点 类型:创建型 想确保任何情况下都绝对只有一个实例 例如:线程池,数据库连接池一般都为单例模式 单例模式优点 在内存中只有一个实例,减少内存开销 可以避免对资源的多重占用 设置全局访问点,严格控制访问

    2024年02月02日
    浏览(71)
  • 03-JAVA设计模式-单例模式详解

    单例模式(Singleton Pattern)是设计模式中的一种,它确保一个类仅有一个实例,并提供一个全局访问点来访问该实例。这种设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 单例模式的应用场景十分广泛,主要涉及需要频繁使用某个对象而又不想重复创建的情况

    2024年04月13日
    浏览(55)
  • Java——单例设计模式

    设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱、“套路”。 经典的设计模式共有23种。每个设计模式均是特定环境下特定问题的

    2024年02月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包