当前位置: 首页 > article >正文

单例模式介绍

何为单例模式

单例模式是针对一个类的设计方式而言,若该类使用了单例模式,那么再整个程序中这个类只会有一个对象,当创建第二个对象时就会直接报错。

即使只能创建一个对象,也会存在例外,即可以通过反射创建第二个实例,但这种情况也基本上不会见到。

如何保证只有一个对象

将该类的构造方法设置为private,之后只能在这个类中创建对象,若要在类外创建对象就会直接报错。

实现单例模式的两种方式以及保证线程安全

1.饿汉式

顾名思义,在这个类一开始,就创建出这个类的对象,代码如下:

class Singleton {

    //实例
    private static Singleton instance = new Singleton();

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

    }

    //获取实例
    public static Singleton getInstance() {
        return instance;
    }
}

当在类外创建对象时,就会直接报错:

当我们在类外获取多个实例时,这些实例均为同一个实例:

 

public class Demo4 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        
        //判断两个实例是否相同
        System.out.println(singleton1 == singleton2);
        
    }
}

在饿汉模式中,由于不涉及写操作,线程就是安全的。

2.懒汉式

顾名思义,在最后才创建出类的实例,甚至不创建实例,下面介绍最后创建实例的情况,代码如下:

class Singleton {

    //先不初始化
    private static Singleton instance = null;

    private Singleton() {

    }

    public static Singleton getInstance() {

        if (instance == null) {//若实例未初始化就先初始化
            instance = new Singleton();
        }
        return instance;
    }
}

可是,上面的代码存在线程安全问题:

1)当线程1判断instance是否为null时,线程2也会判断instance是否为null,由于线程1还未将instance初始化,那么线程1和线程2都会对instance初始化,这样就会造成较大的资源开销,于是我们可以将if语句加锁,代码如下:

class Singleton {

    //先不初始化
    private static Singleton instance = null;
    
    //创建锁对象
    private static Object locker = new Object();

    private Singleton() {

    }

    public static Singleton getInstance() {

        synchronized (locker) {//加锁
            if (instance == null) {//若实例未初始化就先初始化
                instance = new Singleton();
            }
        }
        return instance;
    }
}

2)虽然这时instance的读写操作解决了线程安全的问题,但是由于一进入getInstance方法就会获取锁,导致其他的线程就会阻塞,即使instance已经初始化完成,还是会阻塞,这样就会降低代码执行效率;

我们可以在加锁之前先判断instance是否为null,只有当instance为null时才获取锁,改进代码如下:

class Singleton {

    //先不初始化
    private static Singleton instance = null;

    //创建锁对象
    private static Object locker = new Object();

    private Singleton() {

    }

    public static Singleton getInstance() {

        if (instance == null) {
            synchronized (locker) {
                if (instance == null) {//若实例未初始化就先初始化
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

3)由于instance = new Singleton()操作在CPU上对应多条指令,即操作不是原子的,这样就会引发指令重排序的线程安全问题,可以使用volatile关键字修饰instance以解决指令重排序问题,最终代码如下:

class Singleton {

    //先不初始化
    private static volatile Singleton instance = null;

    //创建锁对象
    private static Object locker = new Object();

    private Singleton() {

    }

    public static Singleton getInstance() {

        if (instance == null) {
            synchronized (locker) {
                if (instance == null) {//若实例未初始化就先初始化
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}


http://www.kler.cn/news/365616.html

相关文章:

  • 钉钉录播抓取视频
  • 详细尝鲜flutter
  • docker搭建mysql多主多从环境
  • 日常记录,使用springboot,vue2,easyexcel使实现字段的匹配导入
  • Python的NumPy库简介
  • php如何对海量数据进行基数统计
  • 基于线性回归(Linear Regression)的房屋价格预测
  • 【华为HCIP实战课程二十】OSPF特殊区域NSSA配置详解,网络工程师
  • 【STM32+HAL】STM32CubeMX学习目录
  • qt QMediaPlaylist
  • ComfyUI初体验
  • 【北京迅为】itop-龙芯2k1000开发指南Linux基础入门vim 编辑器
  • 【linux】ELKB安装token过期
  • arcgis js 怎么加载geoserver发布的wms服务
  • 批处理操作的优化
  • 大数据-190 Elasticsearch - ELK 日志分析实战 - 配置启动 Filebeat Logstash
  • java List对象集合中 如何根据集合中对象某几个属性组合去重
  • 太速科技-527-基于3U VPX XCZU15EG+TMS320C6678的信号处理板
  • 嵌入式MCU面经(突击版)
  • LINUX1.4
  • day05_java中的流程控制
  • 前端实现鼠标可拖动弹框
  • 推荐一些关于计算机网络和 TCP/IP 协议的书籍
  • 【001】调用kimi实现AI对话_#py
  • 隨筆 20241024 Kafka中的ISR列表:分区副本的族谱
  • 利用客户端导入有关联的业务数据(DBeaver+sql)