单例模式---饿汉式、懒汉式

一、什么是单例模式

单例模式,指的是一个类中的对象只能有一个 ,它在内存中只会创建一次对象 的设计模式**。**

二、饿汉式

java 复制代码
public class SingleTon {
    // 私有的构造方法
    private SingleTon() {

    };

    // 1. 饿汉式
    private static SingleTon instance = new SingleTon(); // 一开始就初始化好

    // 线程是安全的,
    // 因为这个实例是一开始就创建好的,无论几个线程来调,他只是读这个instance变量,不存在写
    public static SingleTon getInstance() {  // 对外提供获取这个实例的方法
        return instance;
    }
}

饿汉式的问题是: 一开始就实例化对象,如果实例化过程非常耗时,并且最后这个对象若没有被使用,白白造成资源浪费

三、懒汉式

java 复制代码
public class SingleTonL {
    private SingleTonL() {

    };
    private static SingleTonL instance1 = null;
    // 2.懒汉式  线程是不安全的
    public static SingleTonL getInstance() {
        if  (instance1 == null) {
            instance1 = new SingleTonL();  // 这里面是一个写入的动作
        }
        return instance1;
    }
}

对于懒汉式这一设计模式,线程是不安全的,针对这个问题,给出了解决方案

方案:使用 synchronized****关键字

假如有多个线程中都调用了getInstance方法,那么都走到 if (instance== null) 判断时,可能同时成立,因为instance初始化时默认值是null。这样会导致多个线程中同时创建instance对象,即instance对象被创建了多次,违背了只创建一个instance对象的初衷

java 复制代码
// 解决上述线程不安全的问题
public class SingleTonL1 {
    private SingleTonL1() {

    };

   
    private static SingleTonL1 instance1 = null;
    // 2.懒汉式  线程是不安全的

    public static  SingleTonL1 getInstance() {
        synchronized (SingleTonL1.class) {
                if  (instance1 == null) {
                    instance1 = new SingleTonL1();  // 这里面是一个写入的动作
                }
        }
       
        return instance1;
    }
}

还有一个问题就是如果instance != null , 按照上述代码,这个线程也会进入锁,,,影响执行的效率。需要在前面在进行是否为空判断

java 复制代码
// 解决上述线程不安全的问题
class SingleTonL1 {
    private SingleTonL1() {

    };

    private static SingleTonL1 instance1 = null;
    // 2.懒汉式  线程是不安全的

    public static  SingleTonL1 getInstance() {
        if (instance1 == null) {  // 先判断,如果不为null, 则不用加锁,直接返回
            synchronized (SingleTonL1.class) {
                if  (instance1 == null) {
                    instance1 = new SingleTonL1();  // 这里面是一个写入的动作
                }
            }
        }
        return instance1;
    }
}

多线程下的内存可见性

当A线程更改了变量instance后,线程B又访问,此时需要让线程B访问到的是变量instance的被更改后的值。(也就是说线程B去取这个变量的时候必须从主存取,不能从缓存取。)

解决方案: volatile

相关推荐
小江的记录本14 分钟前
【Spring Boot—— .yml(YAML)】Spring Boot中.yml文件的基础语法、高级特性、实践技巧
xml·java·spring boot·后端·spring·spring cloud·架构
I_LPL18 分钟前
day52 代码随想录算法训练营 图论专题6
java·数据结构·算法·图论
2601_9534656128 分钟前
m3u8live.cn深度解析:一款专为开发者打造的 M3U8 调试工具
java·前端·django·音视频·开发工具
稻草猫.38 分钟前
SpringBoot日志全解析:从调试到持久化
java·开发语言·spring boot·java-ee·idea
zopple38 分钟前
Knife4j文档请求异常(基于SpringBoot3,查找原因并解决)
java·服务器·数据库
清水白石0081 小时前
Python 弱引用深度解析——让缓存不再成为内存泄漏的温床
java·python·缓存
zzb15801 小时前
RAG from Scratch-优化-routing
java·前端·网络·人工智能·后端·python·mybatis
深蓝轨迹1 小时前
IDEA 中 Spring Boot 配置文件的自动提示消失(无法扫描配置文件)的完整解决方案
java·spring boot·intellij-idea
杀神lwz1 小时前
Java Json压缩工具类
java·json
虾..1 小时前
Linux 基于TCP实现服务端客户端通信(线程池)
java·网络协议·tcp/ip