设计模式—单例

作用

保证一个类只有一个实例,并且提供一个访问实例的全局访问点

饿汉式

public class SingletonInstance1 {
	// 声明此类型的变量,并实例化,当该类被加载的时候就完成了实例化并保存在了内存中
	private final static SingletonInstance1 instance = new SingletonInstance1();

	// 私有化所有的构造方法,防止直接通过new关键字实例化
	private SingletonInstance1(){}
	// 对外提供一个获取实例的静态方法
	public static SingletonInstance1 getInstance(){
		return instance;
	}
}

简单实用,推荐使用!

唯一缺点:不管用到与否,类装载时就完成实例化,如果实际没调用,则会造成资源浪费!

懒汉式

什么时候用,什么时候初始化对象

方法锁

public class SingletonInstance2 {
	// 声明此类型的变量,但没有实例化
	private static SingletonInstance2 instance;

	// 私有化所有的构造方法,防止直接通过new关键字实例化
	private SingletonInstance2(){}
	// 对外提供一个获取实例的静态方法,为了数据安全添加synchronized关键字
	public static synchronized SingletonInstance2 getInstance(){
		if(instance == null){
			// 当instance不为空的时候才实例化
			instance = new SingletonInstance2();
		}
		return instance;
	}
}

在方法上添加synchronized关键字,保证多线程安全,但对性能的影响比较大

双重检查

public class SingletonInstance3 {
	// 声明此类型的变量,但没有实例化
	private static volatile  SingletonInstance3 instance;

	// 私有化所有的构造方法,防止直接通过new关键字实例化
	private SingletonInstance3(){}
	// 对外提供一个获取实例的静态方法,
	public static  SingletonInstance3 getInstance(){
		if(instance == null){
			synchronized(SingletonInstance3.class){
				if(instance == null){
					instance = new SingletonInstance3();
				}
			}
		}
		return instance;
	}
}

相比方法锁,通过减小同步代码块的方式提高效率

 不加volatile会有什么问题?

实例化的过程

  1. 分配内存空间
  2. 执行构造方法,实例化对象
  3. 把这个对象赋值给这个空间

如果不加volatile,会执行重排序,比如过程变成了132,这个可能导致其它调用拿到的是未完全实例化的对象 

静态内部类

public class SingletonInstance4 {
	// 静态内部类
	public static class SingletonClassInstance{
		// 声明外部类型的静态常量
		private static final SingletonInstance4 instance = new SingletonInstance4();
	}
	// 私有化构造方法
	private SingletonInstance4(){}

	// 对外提供的唯一获取实例的方法
	public static SingletonInstance4 getInstance(){
		return SingletonClassInstance.instance;
	}
}

通过JVM保证单例,加载外部类时不会加载内部类,这样可以实现懒加载

枚举

public enum SingletonInstance5 {

	// 定义一个枚举元素,则这个元素就代表了SingletonInstance5的实例
	INSTANCE;

}

不仅可以解决线程同步,还可以防止反序列化

posted @ 2022-04-11 21:28  程序员Forlan  阅读(31)  评论(0编辑  收藏  举报