【设计模式-手写源码1】-单例模式

本文详细介绍了Java中的单例模式,包括单例的三种实现方式(懒汉式和饿汉式)及其优缺点。讨论了线程安全问题,并给出了静态构造函数和静态字段实现单例的优化方法。同时,探讨了单例模式在数据库连接池、线程池等场景的应用,以及其在系统资源节省和控制唯一实例方面的优势。然而,单例模式也存在对象扩展困难、不适合变化对象等问题。总结了选择单例模式的考虑因素,并提供了相关参考资料。
摘要由CSDN通过智能技术生成

1:主题拆解

①单例模式(单线程和多线程)

②单例模式的三种写法

③单例模式的优缺点

④单例模式应用场景

2:基本介绍

 一句话描述:某个类只能有一个实例,提供一个全局的访问点。

单例模式比较简单,可以说没有复杂的调用和接口的设计,就是一个简单的类,只是要求这个类只生成一个对象,无论什么时候都要保证这一点,因此只能生成一个实例的模式就是单例模式。3:如何手写一个单例模式

单例模式:保证进程中,类型只有一个实例

  ①构造函数私有化,防止他人实例化

   ②对外提供一个获取实例的途径,公开的静态方法

   ③返回共用一个静态字段

方法一

第一版

    public class Singleton
    { 
        private Singleton()
        { 
            //构造函数私有化
        }
        private static Singleton _Singleton = null;
        public static Singleton CreateInstance()
        {
            if (_Singleton == null)
            {
                _Singleton = new Singleton();
            }
            return _Singleton;
        }
    }

分析:如果对于多线性的访问,此处的会出现类被多次构造的问题,因此需要继续进行改进,加锁用于解决多线程访问的问题

第二版

    public class Singleton
    {
        private Singleton()
        { 
            //构造函数私有化
        }
        private static Singleton _Singleton = null;
        private static readonly object Singleton_Lock = new object();
        public static Singleton CreateInstance()
        {
            lock (Singleton_Lock)
            {
                if (_Singleton == null)
                {
                    _Singleton = new Singleton();
                }
            }
            return _Singleton;
        }
    }

分析:开始多线程初始化,lock锁定,判断对象创建。

但是当类实例化结束之后,再来多个线程请求的时候都需要等待锁。

这无疑是对性能的一种损耗与耗时。因此我们继续做优化

第三版

public class Singleton
    {
        private Singleton()
        { 
            //构造函数私有化
        }
        private static Singleton _Singleton = null;
        private static readonly object Singleton_Lock = new object();
        public static Singleton CreateInstance()
        {
            //对应已经创建,不需要等待锁,直接返回
            if (_Singleton == null)
            {
                lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待
                {
                    if (_Singleton == null)//这个判断不能去掉,保证只初始化一次
                    {
                        _Singleton = new Singleton();
                    }
                }
            }
            return _Singleton;
        }
    }

分析:

这里的两次判断,第一判断:效率,第二判断:避免同步。之所以这样是因为避免加锁后,再次加锁。大大增强了执行效率。

方式二

public sealed class SingletonSecond
    {        
        private SingletonSecond()
        {            
            //构造函数私有化
        }
        private static SingletonSecond _SingletonSecond = null;
       
        static SingletonSecond()
        {
            _SingletonSecond = new SingletonSecond();
        }
        public static SingletonSecond CreateInstance()
        {
            return _SingletonSecond;
        }
    }

分析:静态构造函数,由CLR保证,在第一次使用到这个类型之前,自动被调用且只调用一次

方式三

public sealed class SingletonThird
    {    
        private SingletonThird()
        {
         
        } 
        private static SingletonThird _SingletonThird = new SingletonThird();
        public static SingletonThird CreateInstance()
        {
            return _SingletonThird;
        }
    }

分析:静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次

4:实现方法分析

实现方法分为懒汉式与饿汉式,这个比喻很形象,就好比一个抠脚大汉看待吃饭这件事。

懒汉式可以理解为抠脚大汉饿出生命危险,不吃不行的时候才开始吃饭。

饿汉式可以理解为抠脚大汉只要遇到与吃饭相关的事情,先不管,赶紧开吃。

我们放到上面的三个版本中可以分析得出,

方法一为懒汉式

懒汉式方法总是会出现这样或那样的问题的,因为考虑到了多线程机制,实现起来比较麻烦,并且还会出现问题,就算是使用了一定的解救办法(同步、加锁、双重判断)的办法,性能还是被损耗了,因此懒汉式方法的不推荐使用。

方式二、三为饿汉式

static修饰的方法和属性,所以是在类加载的时候被创建,后期不会再改变,所以线程是安全的。

5:单例模式的优缺点

1:优点

①活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例。

②提供了对唯一实例的受控访问。

③由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。

2:缺点

①不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。

②由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

③滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

6:单例模式的使用场景

数据库连接池

线程池 

流水号生成器   

配置文件读取 

IOC容器实例

7:小结

①当一个类的对象只需要或者只可能有一个时,应该考虑单例模式。

②如果一个类的实例应该在初始化时被创建出来,应该考虑使用饿汉式。

③如果一个类的实例不需要预先被创建,也许这个类的实例并不一定能用得上,也许这个类的实例创建过程比较耗费时间,也许就是真的没必要提前创建。那么应该考虑懒汉式。

④在使用懒汉式单例的时候,应该考虑到线程的安全性问题。

8:参考文章

https://blog.csdn.net/guorui_java/article/details/106585965

https://blog.csdn.net/qq_27525611/article/details/107294099

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不要迷恋发哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值