单例模式
单例即单一的实例
1.概念
- 指某个系统中只存在一个实例,同时提供集中统一的访问接口,以使系统行为保持协调一致。
2.饿汉单例
2.1 场景
- 适用严格把控对象实例化的过程。
2.2 设计思路
-
第一,确保任何人都不能创建对象实例,禁止外部调用构造器,将对象构造器私有化。
-
第二,让对象自己创建自己,使其自有永久拥有自己,将对象自己实例化并使用。
-
private
关键字保证对象实例的私有性、不可见性、不可访问性。 -
static
关键字确保对象的静态性,并在类加载时即初始化,与类同在。该实例在内存中永生,内存垃圾收集器(GC
)也不会对其进行回收。 -
final
关键字确保对象实例是常量,一旦引用被赋值后不能在修改。
-
-
第三,提供外部访问接口。
-
提供一个静态
getInstance()
来获取对象的单例对象。 -
设置
public
关键字暴露,以供外部使用。
-
2.3 范例
-
饿汉造日
package singleton; /** * @author huangdq * @version 1.0.0 * @ClassName Sun.java * @Description 太阳 * @createTime 2022年03月24日 10:20:00 */ public class Sun { // 自有永有单例 public static final Sun sun = new Sun(); // 构造器私有化 private Sun(){ } // 方法公开化 public static Sun getInstance(){ return sun; } }
3.懒汉单例
3.1 场景
- 适用严格把控对象实例化的过程。
3.2 设计思路
-
第一,确保任何人都不能创建对象实例,禁止外部调用构造器,将对象构造器私有化。
-
第二,创建对象,并且将其私有和静态化处理,但不做实例化处理。
-
private
关键字保证对象实例的私有性、不可见性、不可访问性。 -
volatile
关键字确保变量值在各线程访问时的同步性、唯一性。 -
static
关键字确保对象的静态性,并在类加载时即初始化,与类同在。该实例在内存中永生,内存垃圾收集器(GC
)也不会对其进行回收。
-
-
第三,在判空后,加入同步锁
synchronized
以防止多线程多次实例化线程。
3.3 扩展
-
懒加载的“双检锁”
- 这里共采用2个判空嵌套,外层放宽入口,保证线程并发的高效性;内层加锁同步保证实例化的单次运行。不仅达到单例模式的效果还保证运行效率。
-
反例
package singleton; /** * @author huangdq * @version 1.0.0 * @ClassName Sun.java * @Description 太阳 * @createTime 2022年03月24日 10:20:00 */ public class Sun { // 先不进行实例化 public static Sun sun; // 构造器私有化 private Sun() { } // 方法公开化 public static synchronized Sun getInstance() { // 过滤多线程中无日对象 if (sun == null) { sun = new Sun(); } return sun; } }
- 该方法也能实现懒汉设计模式,但这种做法一直进行加锁排队,会造成线程堵塞,造成资源和时间浪费。
3.4 范例
- 懒汉造日
package singleton;
/**
* @author huangdq
* @version 1.0.0
* @ClassName Sun.java
* @Description 太阳
* @createTime 2022年03月24日 10:20:00
*/
public class Sun {
// 先不进行实例化
public volatile static Sun sun;
// 构造器私有化
private Sun(){
}
// 方法公开化
public static Sun getInstance(){
// 过滤多线程中无日对象
if (sun == null) {
// 加锁排队,只需造一个日,保证单例
synchronized (Sun.class){
if (sun == null){
sun = new Sun();
}
}
}
return sun;
}
}
4. 二者对比
-
”饿汉模式“使用静态常量实例化,一般随着类加载而进行实例创建,浪费内存空间;但”饿汉模式“初始化较快,节省
CPU
资源消耗。 -
”懒汉模式“节省内存空间,在需要调用实例后才进行创建,不会造成内存浪费,但是初始化较慢,并且需要注意多并发场景的影响,在并发下考虑加锁等浪费资源,也造成
CPU
的浪费。 -
简而言之,我们更加偏向使用”饿汉模式“设计
5. 运用场景
spring
框架IOC
容器 业务对象管理。