Java设计模式之单例模式简单解析

 更新时间:2023年12月16日 09:41:52   作者:小晨想好好学习  
这篇文章主要介绍了Java设计模式之单例模式简单解析,单例模式的优点在于在内存中某个类只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例,避免对资源的多重暂用,需要的朋友可以参考下

单例模式的优缺点

优点:

  • 在内存中某个类只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
  • 避免对资源的多重暂用

缺点: 没有接口,不能继承

单例模式的几种实现方式

1、饿汉式(线程安全)

类加载时就初始化实例,避免了多线程同步问题,天然线程安全。

为什么饿汉式是线程安全的? 类加载的方式是按需加载,且只加载一次。因此,在上述单例类被加载时,就会实例化一个对象并交给自己的引用,供系统使用,即在线程访问单例对象之前,其就已经创建好了。线程每次都只能拿到这个唯一的对象。因此,饿汉式单例天生就是线程安全的。

class Singleton{
    //1、私有化构造器,这样外部就不能通过构造器来创建对象
    private Singleton(){
    }
    //2、本类内部创建对象实例
    private final static Singleton instance = new Singleton();
    //3、对外提供一个共有的静态方法,返回对象实例
    public static Singleton getInstance(){
        return instance;
    }
}

2、饿汉式(静态代码块方式)

class Singleton{
    //1、私有化构造器,这样外部就不能通过构造器来创建对象
    private Singleton(){
    }
    //2、本类内部创建对象实例
    private static Singleton instance;
    //3、在静态代码块中创建单例对象
    static {
        instance = new Singleton();
    }
    //4、对外提供一个共有的静态方法,返回对象实例
    public static Singleton getInstance(){
        return instance;
    }
}

3、懒汉式(线程不安全)

实例对象在第一次被调用的时候才真正构建的,而不是程序一启动就会自动构建。这种实现最大的问题就是不支持多线程,因为没有加锁 ,多线程场景下不要使用,因为可能会产生多个对象,不再是单例

class Singleton{
    private static Singleton instance;
    private Singleton(){};
    //提供一个静态的公有方法,当使用到该方法时,才会去创建instance
    public static Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}

4、懒汉式+锁 实现多线程安全的单例模式

每次获取实例时,也需要等待其他线程的锁释放,效率低

class Singleton{
    private static Singleton instance;
    private Singleton(){};
    //提供一个静态的公有方法,当使用到该方法时,才会去创建instance
    public static synchronized Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}

5、double-check locking实现单例模式

多个线程只在创建实例的时候加锁实现同步

class Singleton{
    // volatile: 轻量级的synchronized, 由它修饰的变量在发生变化后会立即刷新到主存
    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;
    }
}

【注意】instance为什么需要采⽤ volatile 关键字修饰?

instance采⽤ volatile 关键字修饰也是很有必要的,在上述代码中有下面这一句代码

instance= SingletonDCL();

其实是分为三步执⾏的:

1.为 instance 分配内存空间

2. 初始化 instance

3. 将 instance指向分配的内存地址

但是由于 JVM 具有指令重排的特性,执⾏顺序有可能变成 1->3->2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致⼀个线程获得还没有初始化的实例。

例如,线程A 执⾏了 1 和3,此时线程B调⽤ getInstance() 后发现 instance不为空,因此返回instance,但此时instance还未被初始化,使⽤ volatile 可以禁⽌ JVM 的指令重排 ,保证在多线程环境下也能正常运⾏。

到此这篇关于Java设计模式之单例模式简单解析的文章就介绍到这了,更多相关Java的单例模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring中@Configuration注解和@Component注解的区别详解

    Spring中@Configuration注解和@Component注解的区别详解

    这篇文章主要介绍了Spring中@Configuration注解和@Component注解的区别详解,@Configuration 和 @Component 到底有何区别呢?我先通过如下一个案例,在不分析源码的情况下,小伙伴们先来直观感受一下这两个之间的区别,需要的朋友可以参考下
    2023-09-09
  • spring的pointcut正则表达式的实现

    spring的pointcut正则表达式的实现

    本文主要介绍了spring的pointcut正则表达式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java中生成微信小程序太阳码的实现方案

    Java中生成微信小程序太阳码的实现方案

    这篇文章主要介绍了Java中生成微信小程序太阳码的实现方案,本文讲解了如何生成微信小程序太阳码,通过微信提供的两种方案都可以实现,在实际的项目中建议采用第二种方案,需要的朋友可以参考下
    2022-05-05
  • Java高级架构之FastDFS分布式文件集群详解

    Java高级架构之FastDFS分布式文件集群详解

    这篇文章主要介绍了Java高级架构之FastDFS分布式文件集群详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • SpringData整合ElasticSearch实现CRUD的示例代码(超详细)

    SpringData整合ElasticSearch实现CRUD的示例代码(超详细)

    本文主要介绍了SpringData整合ElasticSearch实现CRUD的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 使用springboot单例模式与线程安全问题踩的坑

    使用springboot单例模式与线程安全问题踩的坑

    这篇文章主要介绍了使用springboot单例模式与线程安全问题踩的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Hadoop之常用端口号解读

    Hadoop之常用端口号解读

    这篇文章主要介绍了Hadoop之常用端口号,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Java连接超时的几种情况以及读取代码

    Java连接超时的几种情况以及读取代码

    在Java编程中连接超时异常是指在建立网络连接时,无法在给定的时间内成功建立连接的异常,这篇文章主要给大家介绍了关于Java连接超时的几种情况以及读取的相关资料,需要的朋友可以参考下
    2024-02-02
  • JAVA实现网络/本地图片转BASE64存储代码示例

    JAVA实现网络/本地图片转BASE64存储代码示例

    这篇文章主要给大家介绍了关于JAVA实现网络/本地图片转BASE64存储的相关资料,Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法,需要的朋友可以参考下
    2023-07-07
  • 登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法

    登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法

    描述一下近期使用EasyConnect遇到的问题,下面这篇文章主要给大家介绍了关于登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-02-02

最新评论