javaDEMO
Java 基础 Demo 站: https://www.javastudy.cloud
Java 中高级开发博客: https://www.lixiang.red
Java 学习公众号: java 技术大本营
单例模式总述
所谓单例,就是全局就一个实例,不用 new,拿来即用,常见的有以下四种方式来使用
不管哪种方式,都要把构造函数给私有化,不准用户自己创建
- 提前实例化对象,然后直接获取
- 在获取的时候进行实例化
- 双重加锁式实例化对象
- 静态内部类来实例化对象
提前实例化对象(饿汉式)
/** * @Author https://www.javastudy.cloud * @CreateTime 2019/11/26 **/ public class Demo { /** * 使用 static 是为了不用new,可以直接使用getDemo方法 * 使用 final 是为了别人不能对这个对象更改 * */ private static final Demo DEMO = new Demo(); /** * 无论哪种方式,构造函数都是私有的 */ private Demo() { } /** * 外面都使用这个方法来获取DEMO实例 */ public static Demo getDemo(){ return DEMO; } }
获取的时候再去初始化(懒汉式)
/** * @Author https://www.javastudy.cloud * @CreateTime 2019/11/26 **/ public class Demo { /** * 使用 static 是为了不用new,可以直接使用getDemo方法 * * */ private static Demo DEMO; /** * 无论哪种方式,构造函数都是私有的 */ private Demo() { } /** * 外面都使用这个方法来获取DEMO实例 * 先进行判空,为空的话先进行初始化 * 不为空的话则直接返回 */ public static Demo getDemo(){ if(DEMO == null){ DEMO = new Demo(); } return DEMO; } }
双层判空(线程安全版)
在上述代码中如线程 A 和线程 B 都执行到 if(DEMO == null )这一行, 然后都得到的为空, 然后就都会 new 一个 Demo 出来,就有两个不同的 DEMO,就不是单例模式了
如此便有了加锁的线程安全的单例模式
/** * @Author https://www.javastudy.cloud * @CreateTime 2019/11/26 **/ public class Demo { /** * 使用 static 是为了不用new,可以直接使用getDemo方法 * * */ private static Demo DEMO; private static final Object lock = new Object(); /** * 无论哪种方式,构造函数都是私有的 */ private Demo() { } /** * 外面都使用这个方法来获取DEMO实例 * 先进行判空,为空的话先进行加锁,然后再进行初始化的过程 * 不为空的话则直接返回 */ public static Demo getDemo(){ if(DEMO == null){ synchronized (lock){ //这里最为关键,见下方解释 if(DEMO == null){ DEMO = new Demo(); } } } return DEMO; } }
在锁内的判空中,如 AB 两个线程都在等待锁,A 先进去初始化, 然后退出来返回. B 进去之后,若不再进行判空,会再重新初始化,这样就不是单例了.
静态内部类
加锁是有开销的,因此有了另外一种线程安全的做法,用静态内部类的方式
/** * @Author https://www.javastudy.cloud * @CreateTime 2019/11/26 **/ public class Demo { private static class InnerSingle{ private static Demo DEMO = new Demo(); } /** * 无论哪种方式,构造函数都是私有的 */ private Demo() { } /** * 直接设用内部类获取实例 */ public static Demo getDemo(){ return InnerSingle.DEMO; } }
这种方式即能做到需要时加载,又能做到线程安全.在外部类加载时,不会立即加载内部类,只有调用 getDemo 时, 才会加载内部类,而且只会加载一次. 在实际开发中,也是以这种方式使用为多.
单例模式使用场景
通常来说,我们会用单例模式来做一些配置,client 等。 如以下场景:
1.调用 Http 的 Httpclient,这个每次初始化都会很重量级,只用初始化一个就可以了。
2.全局配置,从配置文件来初始化一个 Configuration,然后全局调用这一个就可以了
3. 一些工具类,通常来说,我们工具类都是用的 static,但是有些工具类时配置和运行分开的,会那单例获取工具类的配置
综上所述,可以看到,单例模式最大的使用场地还是在配置上面和工具上
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于