首页 > 其他分享 >单例模式之懒汉式

单例模式之懒汉式

时间:2024-07-07 13:26:06浏览次数:15  
标签:Singleton getInstance singleton 模式 public 线程 单例 println 懒汉

文章目录

单例模式(懒汉式)

懒汉式是符合懒加载的模式,但是会存在线程并发的问题发生,所以还需要一种解决线程并发的机制,比如:加锁等

单例模式懒汉式主要的构成是如下

  • 单例类
  • 私有化构造函数(防止实例化)
  • 私有化变量
  • 公共静态获得实例的方法(在调用这个方法的时候才进行实例化)
  • 解决线程并发的机制

代码

懒汉式(线程不安全)

package singleton.type3;

/**
 *
 *
 * @author: Hui
 **/
public class SingletonTest3 {
    
    public static void main(String[] args) {
          Singleton singleton =   Singleton.getInstance();
          Singleton singleton1 =   Singleton.getInstance();
        System.out.println(singleton == singleton1);
        System.out.println(singleton.hashCode());
        System.out.println(singleton1.hashCode());
    }
}

class Singleton{
    
    //1.构造器私有化
    private Singleton(){}
    
    //2.静态实例私有化
    private static Singleton singleton;

    //3.提供实例的静态方法
    public static Singleton getInstance(){
        if (singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

以上方法虽然实现了懒加载,但是线程不安全,在实际开发情况下不能使用。

因为以上代码会出现线程不安全的情况,那么我们如何保证线程安全呢?最简单的就是加锁,在提供实例的静态方法中加锁,就可以保证线程安全了。

懒汉式(线程安全,加锁)

package singleton.type4;
/**
 * @author: Hui
 **/
public class SingletonTest4 {

    public static void main(String[] args) {
        System.out.println("线程安全,加锁");
        Singleton singleton = Singleton.getInstance();
        Singleton singleton1 = Singleton.getInstance();
        System.out.println(singleton == singleton1);
        System.out.println(singleton.hashCode());
        System.out.println(singleton1.hashCode());
    }
}

class Singleton {

    //1.构造器私有化
    private Singleton() {
    }

    //2.静态实例私有化
    private static Singleton singleton;

    //3.提供实例的静态方法
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

虽然解决了线程安全问题,但是性能太差了,每一次调用实例都需要进入同步方法,其实我们创建实例的时候保持同步就可以了。这个方法因为性能比较差,开发过程中不建议使用。

那上述锁的是一个方法,我们可不可以将锁的颗度降低,锁住一个代码块呢?

代码如下

  //3.提供实例的静态方法
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            
            synchronized(Singleton){
                 singleton = new Singleton();
            }
        }
        return singleton;
    }

像以上方法是不是就实现了提高性能呢?是的,但是也出现了线程不安全的问题,比如有多个线程进入 if (singleton == null) 那么是不是会有多个线程进行创建对象。所以为了减少颗粒度又要保证线程安全,我们可以使用双层检查锁来完成!!!

  //3.提供实例的静态方法
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            
            synchronized(Singleton.class){
     			if (singleton == null){
                    singleton = new Singleton();
                } 
            }
        }
        return singleton;
    }

我们只需要在加锁的代码块中再进行一次空判断,就可以很好的解决并发问题了,当一个线程进入的时候,先判断是否为空,为空才创建对象,不为空直接返回。

双重检查锁很好的解决线程不安全问题,并且达到性能的提升。

在实际开发中推荐使用

双重检查锁(线程安全,推荐)

package singleton.type5;

/**
 * @author: Hui
 **/
public class SingletonTest5 {
    public static void main(String[] args) {
        System.out.println("双重检查锁,推荐使用");
        Singleton singleton = Singleton.getInstance();
        Singleton singleton1 = Singleton.getInstance();
        System.out.println(singleton == singleton1);
        System.out.println(singleton.hashCode());
        System.out.println(singleton1.hashCode());
    }
}

class Singleton {

    //1.私有化构造器
    private Singleton() {
    }

    //2.声明静态变量,volatile 保证内存的可见性
    private static volatile Singleton instance;

    public static Singleton getInstance() {

        if (instance == null) {
            synchronized (Singleton.class) {
                //双重检查锁
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }

        return instance;
    }

}

注意变量一定要使用 volatile 修饰,保证变量内存修改时的可见性。

标签:Singleton,getInstance,singleton,模式,public,线程,单例,println,懒汉
From: https://blog.csdn.net/m0_64372868/article/details/140229925

相关文章

  • LVGL一键打包图片工具,全部图片打包成一个bin文件,支持nor flash XIP模式下直接访问数据
    最近做工程项目,需要用到LVGL,但是搜了很长时间没有看到合适的图片打包工具,大多都是生成数组或者单个的bin文件,这样烧录到norflash很麻烦后来看到一篇博客,博主的想法与我类似,不过他后面部分就做的麻烦了,所以,我直接从头写了一个工具,他的博客地址:https://www.wpgdadatong.com.cn/blo......
  • 数据结构题目:模式匹配的BF算法
    1、实验目的键盘输入目标串(主串)s、模式串(子串)t,编写程序,实现顺序串的BF模式匹配算法。2、实验具体要求匹配成功,输出位序,匹配不成功,显示相应提示信息。例如:s=“aababcdcccc”,t=“bcd”。3、实验设计思路(编程语言、模块划分及函数功能描述等)模块划分及函数功能描述:(1)主程序......
  • [Java][设计模式]
    代理模式PROXY静态代理定义一个代理规范,规定代理和目标对象实现同样的方法举个例子,银行柜员和银行都要有取钱的方法,我们才能通过银行柜员去取银行的钱publicinterfaceProxy{voidwithdraw();}publicclassBankimplementsProxy{@Overridepublicvoid......
  • STM32封装ESP8266一键配置函数:实现AP模式和STA模式切换、服务器与客户端创建
    鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)STM32封装ESP8266一键配置函数:实现AP模式和STA模式切换、服务器与客户端创建......
  • 每周一个技能点:责任链模式实现数据多重校验
    定义:责任链模式(ChainofResponsibility):使多个对象都有机会处理同一请求,从而避免请求的发送者和接受者之间的耦合关系,每个对象都是一个处理节点,将这些对象连成一条链,并沿着这条链传递该请求。原始概念中,是直到链上的某个接收对象能够处理它为止。实际使用中,链上的所有对象......
  • 【设计模式之美】改善代码质量之:代码可读性
    文章目录1.把代码分割成更小的单元块2.避免函数参数过多3.勿用函数参数来控制逻辑(ing)4.函数设计要职责单一5.移除过深的嵌套层次6.学会使用解释性变量1.把代码分割成更小的单元块大部分人阅读代码的习惯都是,先看整体再看细节。所以,我们要有模块化和抽象思......
  • C++中的设计模式
    要搞清楚设计模式,首先得要了解UML中的类的一些关系模型。一.UML图中与类的层次关系UML关系:继承关系(泛化关系);组合关系;聚合关系;关联关系;依赖关系;以上关系强度依次减弱。1.继承关系继承关系是最直接的父子关系,如麻雀和老鹰都继承自鸟类,属于子类继承自父类,所以UML中子类实......
  • 关注推送---Feed流,推模式实现的个人分析及其思考。
    本篇文章记录我们实际开发过程中,关注推送场景的个人思考,以及解析。文章目录前言一、关注推送是什么?是什么是Feed流?二、解决关注推送问题的技术方案1.理论模型的选取2.数据类型的选取三、理论模型的选取三、数据类型的选取总结前言⁣⁣⁣⁣⁣⁣⁣⁣本篇文章......
  • 盲返模式:消费即可参与盲返的商业模式
    在当今电商行业的浩瀚蓝海中,盲返模式以其独树一帜的魅力,正悄然引领一股新的消费风尚。这一模式颠覆了传统购物的单一体验,将购物行为转化为一种蕴含惊喜与期待的互动游戏,为电商平台注入了前所未有的活力。盲返模式的精髓,在于其巧妙地将用户购物行为与后续订单的盈利相结合,创造......
  • [图解]企业应用架构模式2024新译本讲解19-数据映射器1
    100:00:01,720-->00:00:03,950下一个我们要讲的就是200:00:04,660-->00:00:07,420数据映射器这个模式300:00:09,760-->00:00:13,420这个也是在数据源模式里面400:00:13,430-->00:00:14,820用得最广泛的500:00:16,250-->00:00:19,170大多数都是用600:......