4.6 KiB
4.6 KiB
Java 单例设计模式详解
参考自慕课网课程:Java设计模式精讲⭐⭐⭐⭐⭐
1、单例模式的饿汉模式(线程安全)
缺点:在类初始化时候就会初始化对应的单例类,如果单例类没有被用到且单例类初始化复杂,就不应用这种模式
public class HungrySingleton {
private static final HungrySingleton hungrySingleton;
private HungrySingleton(){
// 如果不加上这个判断,就会被反射攻击
if (hungrySingleton!=null){
throw new RuntimeException("单例模式禁止反射调用!");
}
}
static {
hungrySingleton=new HungrySingleton();
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
// 反射攻击
public class ReflectAttack {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 反射攻击
Class<HungrySingleton> hungrySingletonClass = HungrySingleton.class;
Constructor<HungrySingleton> constructor = hungrySingletonClass.getDeclaredConstructor();
// 获取可操作权限
constructor.setAccessible(true);
HungrySingleton hungrySingleton = constructor.newInstance();
HungrySingleton instance = HungrySingleton.getInstance();
System.out.println(hungrySingleton==instance);
}
}
2.单例模式的懒汉模式(线程不安全)
public class LazySingleton {
private static LazySingleton lazySingleton=null;
private LazySingleton(){
if (lazySingleton!=null){
throw new RuntimeException("单例模式禁止反射调用!");
}
}
// 在多线程下是不安全的
public static LazySingleton getInstance(){
if (lazySingleton!=null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
}
3.单例模式的懒汉模式(采用双重检查锁,线程安全)
public class LazySingleton {
// 必须要声明为 volatile 防止指令重排序
private static volatile LazySingleton lazySingleton = null;
private LazySingleton() {
if (lazySingleton != null) {
throw new RuntimeException("单例模式禁止反射调用!");
}
}
public static LazySingleton getInstance() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
if (lazySingleton == null) {
/*
new对象过程:
1.分配内存给这个对象
2.初始化对象
3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
上述三步会发生指令重排序
*/
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
4.使用枚举实现单例(推荐 JVM保证下的单例)
能够防止反射攻击和序列化对单例的破坏
// 枚举单例模式
public enum EnumInstance {
INSTANCE;
public static EnumInstance getInstance() {
return INSTANCE;
}
}
// 测试
public class Test {
public static void main(String[] args) {
EnumInstance instance0 = EnumInstance.INSTANCE;
EnumInstance instance1 = EnumInstance.getInstance();
EnumInstance instance2 = EnumInstance.getInstance();
System.out.println(instance0 == instance1); // true
System.out.println(instance0 == instance2); // true
System.out.println(instance1 == instance2); // true
}
}
public enum EnumInstance {
INSTANCE;
private String data;
// 可以增加对应的方法
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
public static EnumInstance getInstance() {
return INSTANCE;
}
}
5.容器式单例(不常用)
public class ContainerSingleton {
private ContainerSingleton(){
}
private static Map<String,Object> singletonMap = new HashMap<String,Object>();
public static void putInstance(String key,Object instance){
if(StringUtils.isNotBlank(key) && instance != null){
if(!singletonMap.containsKey(key)){
singletonMap.put(key,instance);
}
}
}
public static Object getInstance(String key){
return singletonMap.get(key);
}
}