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

一、什么是单例模式

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

二、饿汉式

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

相关推荐
SimonKing7 分钟前
消息积压、排查困难?Provectus Kafka UI 让你的数据流一目了然
java·后端·程序员
考虑考虑12 分钟前
点阵图更改背景文字
java·后端·java ee
ZHE|张恒19 分钟前
Spring Boot 3 + Flyway 全流程教程
java·spring boot·后端
TDengine (老段)44 分钟前
TDengine 数学函数 CRC32 用户手册
java·大数据·数据库·sql·时序数据库·tdengine·1024程序员节
心随雨下1 小时前
Tomcat日志配置与优化指南
java·服务器·tomcat
Kapaseker1 小时前
Java 25 中值得关注的新特性
java
wljt1 小时前
Linux 常用命令速查手册(Java开发版)
java·linux·python
撩得Android一次心动1 小时前
Android 四大组件——BroadcastReceiver(广播)
android·java·android 四大组件
canonical_entropy1 小时前
Nop平台到底有什么独特之处,它能用在什么场景?
java·后端·领域驱动设计
chilavert3181 小时前
技术演进中的开发沉思-174 java-EJB:分布式通信
java·分布式