Java设计模式【单例模式】

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

Java设计模式【单例模式】

Java设计模式【单例模式】

单例模式

单例模式(Singleton Pattern)是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供对该实例的唯一访问点。

优缺点

优点:

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

  2. 由于在系统内存中只存在一个对象,因此可以节约系统资源。

缺点

  1. 单例类的扩展有很大的困难。

  2. 单例类的职责过重,在一定程度上违背了“单一职责原则”。

  3. 对象生命周期。 单例模式没有提出对象的销毁,在提供内存的管理的开发语言中,只有单例模式对象自己才能将对象实例销毁,因为只有它拥有对实例的引用。 在各种开发语言中,比如C++,其他类可以销毁对象实例,但是这么做将导致单例类内部的指针指向不明。

单例模式的使用

饿汉模式

  1. 静态成员变量
/**
 * @author Physicx
 * @date 2023/5/12 下午10:13
 * @desc 单例
 * Created with IntelliJ IDEA
 */
public class Singleton {

    //初始化实例对象
    private static final Singleton instance = new Singleton();

    //私有化构造方法
    private Singleton() {
    }

    //提供获取实例对象方法
    public static Singleton getInstance() {
        return instance;
    }

}
  1. 静态代码块
/**
 * @author Physicx
 * @date 2023/5/12 下午10:13
 * @desc 单例
 * Created with IntelliJ IDEA
 */
public class Singleton {

    //实例对象
    private static final Singleton instance;

    static {
        instance = new Singleton();
    }

    //私有化构造方法
    private Singleton() {
    }

    //提供获取实例对象方法
    public static Singleton getInstance() {
        return instance;
    }

}

饿汉式单例的写法适用于单例对象较少的情况,这样写可以保证绝对的线程安全,执行效率比较高。但是缺点也很明显,饿汉式会在类加载的时候就将所有单例对象实例化,这样系统中如果有大量的饿汉式单例对象的存在,系统初始化的时候会造成大量的内存浪费,换句话说就是不管对象用不用,对象都已存在,占用内存。

懒汉模式

public class Singleton {

    //实例对象
    private static Singleton instance;

    //私有化构造方法
    private Singleton() {
    }

    //提供获取实例对象方法(线程安全)
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

线程安全的一种懒汉式写法,在类第一次使用的时候初始化,获取实例的静态方法由synchronized修饰,所以是线程安全的。这种方法每次获取实例对象都加锁同步,效率较低。

双重检测机制(DCL)

public class Singleton {

    //实例对象
    private static volatile Singleton instance;

    //私有化构造方法
    private Singleton() {
    }

    //提供获取实例对象方法
    public static Singleton getInstance() {
        if (instance == null) {
            //加锁处理
            synchronized (Singleton.class) {
                if (instance==null) {
                    //初始化
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

实例对象必须用 volatile 修饰,否则极端情况可能出现安全隐患。

以上初始化对象代码被编译后会变成以下三条指令:

  1. 分配对象的内存空间。

  2. 初始化对象。

  3. 设置instance指向刚才分配的内存空间。

如果按照上面的执行顺序则不加volatile没有问题,但是CPU或编译器为了提高效率,可能会进行指令重排,最终顺序变为:

  1. 分配对象的内存空间。

  2. 设置instance指向刚才分配的内存空间。

  3. 初始化对象。

当两个线程同时获取实例对象时,线程A已经将instance指向分配空间但未初始化对象,线程B此时第一次判空已不为空,于是返回instance实例,但是此时返回的实例未初始化会导致后续空指针异常。

DCL这种方式同样也是类第一次使用的时候初始化,初始化代码synchronized修饰线程安全,这种方式只会第一次实例对象才会进行同步,因此效率高。

《Java Concurrency in Practice》作者Brian Goetz在书中提到关于DCL的观点:促使DCL模式出现的驱动力(无竞争同步的执行速度很慢,以及JVM启动时很慢)已经不复存在,因而它不是一种高效的优化措施。延迟初始化占位类模式(静态内部类)能带来同样的优势,并且更容易理解。

静态内部类(延迟初始化)

public class Singleton {

    //私有化构造方法
    private Singleton(){}

    //静态内部类(被调用时加载)
    private static class SingletonHandle {
        private static final Singleton instance = new Singleton();
    }

    //提供获取实例对象方法
    public static Singleton getInstance() {
        return SingletonHandle.instance;
    }

}

利用静态内部类被调用时才加载的特性,通过静态初始化初始Singleton对象,由于JVM将在初始化期间获得一个锁,并且每个线程都至少获取一次这个锁以确保这个类已经加载,因此在静态初始化期间,内存写入操作将自动对所有线程可见。因此无论是在被构造期间还是被引用时,静态初始化的对象都不需要显式的同步。

线程安全,效率高,使用的时候才会初始化不浪费内存。

《Java Concurrency in Practice》作者Brian Goetz 推荐这种单例实现方式。

枚举实现方式

除了以上几种常见的实现方式之外,Google 首席 Java 架构师、《Effective Java》一书作者、Java集合框架的开创者Joshua BlochEffective Java一书中提到:单元素的枚举类型已经成为实现Singleton的最佳方法

在这种实现方式中,既可以避免多线程同步问题;还可以防止通过反射和反序列化来重新创建新的对象。

public class Singleton {

    //私有化构造方法
    private Singleton() {}

    enum SingletonEnum {
        SINGLETON;
        private final Singleton instance;

        SingletonEnum() {
            instance = new Singleton();
        }
        //提供获取实例对象方法
        public Singleton getInstance() {
            return instance;
        }
    }

}

调用方式如下:

public static void main(String[] args) {
        Singleton instance1 = Singleton.SingletonEnum.SINGLETON.getInstance();
        Singleton instance2 = Singleton.SingletonEnum.SINGLETON.getInstance();
        System.out.println(instance2 == instance1);
    }

普通的单例模式是可以通过反射和序列化/反序列化来破解的,jvm虚拟机会保证枚举类型不能被反射并且构造函数只被执行一次,而Enum由于自身的特性问题,是无法破解的。当然,由于这种情况基本不会出现,因此我们在使用单例模式的时候也比较少考虑这个问题。

总结

实现方式 优点 缺点
饿汉模式 线程安全,效率高 非懒加载
懒汉模式 线程安全,懒加载 效率低
双重检测机制 线程安全,懒加载,效率高
静态内部类 线程安全,懒加载,效率高
枚举 线程安全,效率高 非懒加载

由于单例模式的枚举实现代码比较简单,而且又可以利用枚举的特性来解决线程安全和单一实例的问题,还可以防止反射和反序列化对单例的破坏,因此在很多书和文章中都强烈推荐将该方法作为单例模式的最佳实现方法

参考:单例模式详解(知乎文章)

补充说明

后续会依次更新 详解java 23种设计模式,欢迎关注、交流、补充相关内容(如下)。文章来源地址https://www.toymoban.com/news/detail-440825.html

快捷导航
设计模式简介总结
单例模式详解
工厂方法模式
抽象工厂模式

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

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

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

相关文章

  • 设计模式篇(Java):单例模式

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

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

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

    2024年01月24日
    浏览(51)
  • java设计模式-单例

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

    2024年01月18日
    浏览(53)
  • 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基础之设计模式(单例模式,工厂模式)

    是一种编码套路 单例模式 一个类只能创建一个实例 饿汉式 直接创建唯一实例 缺点: 有可能浪费空间 懒汉式 在获取实例是创建唯一对象 缺点: 线程效率慢 懒汉式-进阶版 在懒汉式的基础上,利用同步代码块结合二次校验提高执行效率 工厂模式 是一种底层技术,通常用于底层框

    2024年01月18日
    浏览(45)
  • Java——单例设计模式

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

    2024年02月11日
    浏览(46)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包