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

4.13--设计模式之创建型之单例模式(总复习版本)---脚踏实地,一步一个脚印

**

一、什么是单例模式

:**

一个类只有一个实例,且该类能自行创建这个实例的一种模式

单例模式特点:
①单例类只有一个实例对象
②该单例对象必须由单例类自行创建
③单例类对外提供一个访问该单例的全局访问点

二、饿汉式单例:

类一旦加载就创建一个单例,保证在调用getInstance方法之前单例已经存在,这种饿汉式单例会造成空间浪费(线程安全)

//饿汉式单例类.在类初始化时,已经自行实例化 
public class Singleton1 {
    private Singleton1() {}
    private static final Singleton1 single = new Singleton1();
    //静态工厂方法 
    public static Singleton1 getInstance() {
        return single;
    }
}

三、懒汉式单例:

为了避免内存空间浪费,采用懒汉式单例,即用到该单例对象的时候再创建。

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    //静态工厂方法 
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

Singleton 通过私有化构造函数,避免类在外部被实例化,而且只能通过 getInstance() 方法获取 Singleton 的唯一实例。
但是懒汉式单例的实现是线程不安全的,在并发环境下可能出现多个 Singleton 实例的问题。

要实现线程安全,有以下三种方式,都是对 getInstance() 这个方法改造,保证了懒汉式单例的线程安全:

1、在 getInstance() 方法上加同步机制:

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

在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的

2、双重检查锁定:

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private volatile static Singleton singleton=null;
    
    public static Singleton getInstance() {
        if (singleton == null) {  
            synchronized (Singleton.class) {  
               if (singleton == null) {  
                  singleton = new Singleton(); 
               }  
            }  
        }  
        return singleton; 
    }
}

1.为什么 getInstance() 方法内需要使用两个 if (singleton == null) 进行判断呢?

假设高并发下,线程A、B 都通过了第一个 if 条件。若A先抢到锁,new 了一个对象,释放锁,然后线程B再抢到锁,此时如果不做第二个 if 判断,B线程将会再 new 一个对象。使用两个 if 判断,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。

2.volatile 关键字的作用?

volatile 的作用主要是禁止指定重排序。假设在不使用 volatile 的情况下,两个线程A、B,都是第一次调用该单例方法,线程A先执行 singleton = new Singleton(),但由于构造方法不是一个原子操作,编译后会生成多条字节码指令,由于 JAVA的 指令重排序,可能会先执行 singleton 的赋值操作,该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,之后 singleton 便不为空了,但是实际的初始化操作却还没有执行。如果此时线程B进入,就会拿到一个不为空的但是没有完成初始化的singleton 对象,所以需要加入volatile关键字,禁止指令重排序优化,从而安全的实现单例。

3、静态内部类:

public class Singleton {  
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}  

利用了类加载机制来保证初始化 instance 时只有一个线程,所以也是线程安全的,同时没有性能损耗


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

相关文章:

  • 面试篇-揭开Spring Bean加载的神秘面纱
  • C++ 指针与引用详解
  • 2022国赛16:神州路由器交换机BGP配置实例1
  • 计算机网络 - UDP协议 与 TCP协议可靠性(传输层)
  • OpenCV实战之人脸美颜美型(六)——磨皮
  • UTF-8(Unicode Transformation Format)
  • 「她时代」背后的欧拉力量
  • BUUCTF--Web篇详细wp
  • (十一)排序算法-选择排序
  • 更新按日期分表,多个表添加字段
  • 四、JS04 初识 jQuery
  • HTTP API接口设计规范
  • java ssm学生网上作业提交系统
  • 【ROS2指南-15】创建自定义消息统一管理包
  • 【grpc03】proto文件介绍
  • SQL的函数
  • centos新系统新挂载原硬盘方法
  • SpringMVC基本注解的使用和理解
  • OA系统的功能和作用是什么(OA系统百科)
  • cube-studio AI平台 提供开源模型示例列表(3月份)
  • 数据治理之元数据管理
  • Golang 多版本安装小工具G
  • 2023MathorCup数模A题思路数据代码论文【全网最全分享】
  • Python轻量级Web框架Flask(5)——Flask模型基础和数据迁移
  • 2023年MathorCup数学建模C题电商物流网络包裹应急调运与结构优化问题解题全过程
  • 2023-04-16 学习记录--C/C++-邂逅C/C++
  • 这篇文章价值很大:股票历史分时成交数据怎么简单获取?【干货】
  • 2023年七大最佳勒索软件解密工具
  • C#基础复习
  • 轨道交通信号系统介绍