强烈建议用枚举实现单例模式

懒汉式写法,包含演进过程,通过双重检查和静态方法实现的方式保证线程安全;

//1.懒汉式(延迟加载)
//线程不安全写法
public class Methods{
	private Methods{};
	private static Methods instance = null;
	//获取单例
	public static Methods getInstance(){
		if(instance==null){
			return new Methods();
		}
		return instance;
	}	
}
//双重检查方式写法
public class Methods{
	private Methods{};
	private static Methods instance = null;
	//获取单例
	public static Methods getInstance(){
		if(instance==null){
			//如果为null也只有一个线程能进入,不满足条件最终走最外部的那个return
			synchronized(Methods.class){
				if(instance==null){
					return new Methods();
				}
			}
		}
		return instance;
	}	

}
//上述的写入在synchronized里面的代码 存在指令重排序的问题,如果先给instance分配内存地址,然后再去实例化对象,这样先进入到线程已经复制,后进入的线程也无法获取到
//双重加锁 防止指令重排序的写法
public class Methods{
	private Methods{};
	private volatile static  Methods instance = null;
	//获取单例
	public static Methods getInstance(){
		if(instance==null){
			//如果为null也只有一个线程能进入,不满足条件最终走最外部的那个return
			synchronized(Methods.class){
				if(instance==null){
					return new Methods();
				}
			}
		}
		return instance;
	}	

}
//基于静态内部类的实现 原理是类初始化的时候,只有一个类能获取到类初始化锁
public class Methods{
	private Methods{};
	private static class InnerMethods{
		private static Methods methods = new Methods{};
	}
	public static Methods getInstance(){
		return InnerMethods.methods;
	}
	
}

饿汉式写法很简单,饿汉式最大的缺点就是没有延迟加载的效果,如果一个单例从项目启动一直都没有被使用,会造成很大内存浪费;

//2.饿汉式(没有延迟加载的效果)
public class Methods{
	private final static Methods methods = new Methods();
	private Methods{};
	public static Methods getInstance(){
		return methods;
	}
	
}

既然饿汉式和懒汉式的写法看似已经非常完美了,那为何还需要强调使用枚举来实现单例模式;原因在于上述两种实现方式有两个很大的问题,就是序列化破坏和反射攻击;

序列化攻击:利用单例获取的对象进行序列化,然后在将序列化的对象反序列化,对比两者不相同;

反射攻击:同样的道理,通过反射获取到的对象和实例化的对象,两者不相等;

小伙伴可以亲自试一试便知道,至于具体是什么原因导致的,由于篇幅原因,这里不赘述,小伙伴可以参考网上相关的资料;

那么我们如何才能解决上述两个问题呢,那就是我们这篇博客的主题,通过枚举的方式实现单例模式;代码也非常简洁;

public enum Methods{
	INSTANCE;
	
	public static Methods getInstance(){
	  return INSTANCE; 
	}
	
}
发布了58 篇原创文章 · 获赞 3 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Min_Chander/article/details/104387924