仅为记录,仅供参考
单例模式
单例模式的定义
确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
单例模式的作用
有些类只需要被实例化一次。例如任务管理器窗口,只能有一个状态,如果实例化多个。如果都一样,就是浪费内存,如果不一样,就违反了它的设计要求,同时存在多个状态。
单例模式结构
- 定义一个私有的构造函数(如图LoadBalancer),覆盖之前的默认存在的构造函数,私有是为了防止其他类调用。
- 定义一个私有的静态成员变量(如图instance)私有防止在类外面被修改。静态为了在此类生成的所有对象中共享该变量。假如不用静态变量。生成一个对象,它的静态变量将再次被初始化,也就是例中的null。接下来的公有静态成员方法里面的if语句将永为真。
- 定义一个公有的静态成员方法,方法里判断私有静态变量是否为null,为null则实例化这个类。(如图getLoadBalancer)
单例模式分类
饿汉式单例类
- 定义一个静态的final变量(如图instance),然后实例化一个这个类放进去,静态,在此类生成的所有对象中共享该变量。final变量,不允许修改
- 定义一个私有的构造方法(如图EagerSingleton),避免被其他类调用
- 定义一个公有的静态成员方法(如图getInstance),一调用就返回之前那个变量instance
懒汉式单例类
- 定义一个私有的静态成员变量(如图instance),但没有final,后面还可以修改
- 定义一个私有的构造方法
- 定义一个公有的成员方法,在里面实例化这个类放到变量instance,然后返回instance
成员方法里面为了防止多次实例化,还要判断变量instance是否为空。但是仅仅判断一次还不够。
有可能会出现下面这种情况:有可能会有多个线程同时调用
我们应该在成员方法前面加一个synchronized关键字,对方法加锁,保证只有一个线程可执行该方法
这样每次调用该成员方法都要进行线程锁定判断,在多线程高并发访问环境中将会导致系统性能大大降低。所以我们可能会想到,缩小锁的范围
把synchronized关键字放在那个实例化类的语句之前。但是这样会导致几个类都已经执行过if判断语句了,等着执行实例化类的语句。这样会导致if语句失去作用。
所以要把if语句再加一个到里面去。那外面的if语句有什么用呢?如果不满足外面的条件就不需要加锁。线程不需要等待。
由于写了两个if,在Java环境中会被优化,不能给它优化,要加个关键字volatile
懒汉式和饿汉式的区别
- 懒汉式把实例化对象放在方法里。你要调用方法的时候,它才会给你实例化对象。
- 而饿汉式对象一上来就实例化对象,放在一个final的静态变量中,需要使用的时候调用他的成员方法就返回这个变量。
- 懒汉式需要双重锁,在多线程高并发环境中将会导致系统性能大大降低
- 饿汉式一上来就创建,也需要耗内存
单例模式优缺点
优点
- 提供了对唯一实例的受控访问
- 节约系统资源(由于系统内存中只存在一个对象)
- 允许可变项目的实例,基于单例模式的扩展(例如定义一个私有的静态成员变量,开始设为0,然后每实例化一个对象就+1,然后设个值,超过这个就不能执行实例化的方法)
缺点
- 没有抽象层
- 单个类职责过重
- 很多面向对象语言都提供自动垃圾回收技术,实例化的共享对象长时间不被利用,会被自动销毁并回收资源。下次利用时又将重新实例化,将导致共享的单例对象状态的丢失