玩转设计模式(单例模式)(设计模式实战)
序言
单例模式在实际工作中的应用场景非常多,概念非常简单,就是整个程序中,有且只允许有一个实例。例如:我们程序中存放一个当前用户信息的类,我们使用单例模式,可以确保在任何页面获取信息时拿的都是同一个对象,这样可以保持状态的一致性。
单例模式的类型
也许会有疑惑,单例模式为啥还会有类型,这是因为实例的创造时机导致。
懒汉式:只有在需要使用时,才去创建实例
饿汉式:在类加载时就先创建好,等待被使用
懒汉式创建单例对象
懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象。否则则先执行实例化操作。
public class Singleton { private static Singleton singleton; private Singleton(){} public static Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } }复制代码
以上方式其实还会存在一个隐形问题,就是如果两个线程同时判断singleton
为null,那么他们都会去实例化一个对象,这样就成了多例。所以,我们要解决的是线程安全问题。
我们常用的方法,就是加个锁
public static synchronized Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } // 或者 public static Singleton getInstance() { synchronized(Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } return singleton; }复制代码
这样就规避了两个线程同时创建Singleton对象的风险。
但是引来另外一个问题:每次去获取对象都需要先获取锁,并发性能非常地差,极端情况下,可能会出现卡顿现象。 所以我们提出优化设想:目标是如果没有实例化对象则加锁创建,如果已经实例化了,则不需要加锁,直接获取实例
public static Singleton getInstance() { if (singleton == null) { // 线程A和线程B同时看到singleton = null,如果不为null,则直接返回singleton synchronized(Singleton.class) { // 线程A或线程B获得该锁进行初始化 if (singleton == null) { // 其中一个线程进入该分支,另外一个线程则不会进入该分支 singleton = new Singleton(); } } } return singleton; }复制代码
饿汉式创建单例对象
饿汉式在加载时已经创建好该对象,在程序调用时直接返回该单例对象即可,即我们在编码时就要马上创建这个对象,不需要等到被调用时再去创建。
public class Singleton{ private static final Singleton singleton = new Singleton(); private Singleton(){} public static Singleton getInstance() { return singleton; } }复制代码
注意上面的代码在第3行已经实例化好了一个Singleton对象在内存中,不会有多个Singleton对象实例存在
类在加载时会在堆内存中创建一个Singleton对象,当类被卸载时,Singleton对象也随之消亡了。
作者:coolFish
链接:https://juejin.cn/post/7036009322492461064
伪原创工具 SEO网站优化 https://www.237it.com/