单例模式 (懒汉,饿汉,线程安全的懒汉)

这个专栏 主要分享和记录一些之前我对设计模式的学习和理解。希望可以帮助到之前不了解设计模式的新手

单例模式

首先什么叫单例模式?

就是:

无论在代码的哪个地方,通过相同的方式获取该类的实例,都将获得同一个对象。

那么哪些场景下面 我们需要搞这种 比如获取多次之后 必须包装获取到的是同一个对象呢?

共享资源:当多个对象需要访问和共享同一资源时,使用单例模式可以确保只有一个实例管理和提供该资源,避免资源的重复创建和浪费,例如数据库连接池、线程池等。

配置信息:单例模式可以用于管理全局的配置信息,确保在整个应用程序中配置信息的一致性和可靠性。例如,全局的系统配置、日志配置等。

缓存对象:在需要缓存大量对象时,使用单例模式可以提供一个全局的缓存管理器,确保缓存对象的一致性和可控性。例如,页面缓存、数据缓存等。

日志记录器:使用单例模式可以实现全局唯一的日志记录器,方便在应用程序的各个部分记录日志,并统一管理日志的输出格式和级别。

对象工厂:当需要限制某个类只能有一个实例,并提供全局访问时,可以使用单例模式作为对象工厂。这样可以确保只有一个实例被创建,并提供统一的访问点。


先了解了背景,然后我们再说实现:
为了照顾新手 我们一步一步的讲

我们在java中无时无刻不在创建对象 获取某个类的实例 比如你创建了一个类A:

A a = new A();

可以了这就创建了一个关于class A 的实例对象。假设这个A里面装的就是数据库连接配置的东西

那我再创建一个

A a1 = new A();

现在问题来了 a 和a1 是不是同一个对象?
肯定不是对吧 因为你已经new了2次了。你每new一次 就创建了一个新对象。

所以第一点至少明确了 我们要实现你创建2次 获得的是同一个对象,肯定不能用new的方式。

这时候我们想到了 static 静态修饰。 被static静态修饰的变量 它属于类本身不属于类的实例。它是可以之间类名.调用的

所以我们这样写:

/**
 * 饿汉式 单例模式
 * */
public class Singleton1 {

    //构造方法设为私有
    private Singleton1(){}

    //创建一个本类的对象
    private static Singleton1 singletonInstance = new Singleton1();
    
    //提供一个外界可以访问的方式
    public static Singleton1 getInstance(){
        return singletonInstance;
    }

}

getInstance方法对外提供一个口子,外界可以调用它来创建一个singletonInstance。
这就是饿汉式 单例模式。

这种模式有点浪费 ,浪费在哪里呢?外界还没有调用你的时候 你在类加载里面已经把成员变量Singleton1 给实例化了。

等于是你每次都要实例化它——你每天都要做一顿饺子 不管有没有人来吃 每人来吃 就浪费了

所以我们改进:

/**
 * 懒汉式 线程不安全 单例模式
 * */
public class Singleton2 {

    //构造方法设为私有
    private Singleton2(){}

    //创建一个本类的对象
    private static Singleton2 singletonInstance;
    //提供一个外界可以访问的方式
    public static Singleton2 getInstance(){
        if (singletonInstance==null) {
            singletonInstance = new Singleton2();
       }
        return singletonInstance;
    }

}

它调用getInstance方法的时候 我们再创建——你每天只有等来人的时候 才做饺子 来一个做一顿 不浪费。

但是这里牵扯到一个线程安全问题:

你看 比如现在1万个线程同时并发访问getInstance方法,那么就可能出现多个线程一起执行了 if (singletonInstance==null) ,这时候多个线程 都执行到里面 谁都还没结束 没出这个if(){。。。。}。 那么久出现了创建了多个对象。

这就是线程不安全的问题

所以我们把这一块 singletonInstance = new Singleton2(); 给他 直接用悲观锁 锁住。

意味着多线程走到这里的时候 就变成了一个一个一个排队执行。

/**
 * 懒汉式 线程安全 单例模式
 * */
public class Singleton3 {

    //构造方法设为私有
    private Singleton3(){}

    //创建一个本类的对象
    private static volatile Singleton3 singletonInstance;

    //提供一个外界可以访问的方式
    public static Singleton3 getInstance(){
        //如果为null 可能出现线程安全问题
        if (singletonInstance==null) {
            synchronized (Singleton3.class) {
                if (singletonInstance==null) {
                    singletonInstance = new Singleton3();
                }
            }
       }

        //如果不为null 不需要考虑线程安全问题
        return singletonInstance;
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值