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,但是有些工具类时配置和运行分开的,会那单例获取工具类的配置
综上所述,可以看到,单例模式最大的使用场地还是在配置上面和工具上
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于