设计模式23之 单例模式


饿汉式 DCL懒汉式

1.饿汉式

package JUC;

/**
 * 饿汉式 浪费内存
 */
public class SingletonHungry {
    
    
	
	private byte[] data1 = new byte[1024*1024];
	private byte[] data2 = new byte[1024*1024];
	private byte[] data3 = new byte[1024*1024];
	private byte[] data4 = new byte[1024*1024];

	private SingletonHungry() {
    
    
		System.out.println(Thread.currentThread().getName());
	}
	
	private final static SingletonHungry HUNGRY = new SingletonHungry();
	
	public static SingletonHungry getInstance() {
    
    
		return HUNGRY;
	};
	
	public static void main(String[] args) {
    
    
		for (int i = 0; i < 10; i++) {
    
    
			new Thread(()->{
    
    
				SingletonHungry.getInstance();
			}).start();
		}
	}
}

2.懒汉式

package JUC;
/**   
 * 懒汉式单例 双重检测锁+volatile防止指令重排 
 */
public class SingletonLazyMan {
    
    

	private SingletonLazyMan(){
    
    
		System.out.println(Thread.currentThread().getName());
	}
	
	private volatile static SingletonLazyMan lazyMan; 
	
	//双重检测锁 DCL懒汉式
	public static SingletonLazyMan getInstance() {
    
    
		if (lazyMan==null) {
    
    
			synchronized (SingletonLazyMan.class) {
    
    
				if (lazyMan==null) {
    
    
					lazyMan = new SingletonLazyMan();
					/**
					 * 不是原子性操作
					 * 1.分配内存空间
					 * 2.执行构造方法,初始化对象
					 * 3.把对象指向这个空间
					 * 
					 * 指令重排 123  
					 * 但是如果执行132 A
					 * 				B
					 */
				}
			}
		}
		return lazyMan; //此时SingletonLazyMan还没有完成构造
	}
	
	public static void main(String[] args) {
    
    
		for (int i = 0; i < 10; i++) {
    
    
			new Thread(()->{
    
    
				SingletonLazyMan.getInstance();
			}).start();
		}
	}
}

2.1反射破坏单例

package JUC;

import java.lang.reflect.Constructor;

/**   
 * 懒汉式单例 双重检测锁+volatile防止指令重排 
 */
public class SingletonLazyMan {
    
    

	private SingletonLazyMan(){
    
    
		System.out.println(Thread.currentThread().getName());
	}
	
	private volatile static SingletonLazyMan lazyMan; 
	
	//双重检测锁 DCL懒汉式
	public static SingletonLazyMan getInstance() {
    
    
		if (lazyMan==null) {
    
    
			synchronized (SingletonLazyMan.class) {
    
    
				if (lazyMan==null) {
    
    
					lazyMan = new SingletonLazyMan();
					/**
					 * 不是原子性操作
					 * 1.分配内存空间
					 * 2.执行构造方法,初始化对象
					 * 3.把对象指向这个空间
					 * 
					 * 指令重排 123  
					 * 但是如果执行132 A
					 * 				B
					 */
				}
			}
		}
		return lazyMan; //此时SingletonLazyMan还没有完成构造
	}
	
	public static void main(String[] args) throws Exception, SecurityException {
    
    
		SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
		Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
		constructor.setAccessible(true);
		SingletonLazyMan lazyMan2 = constructor.newInstance();
		
		if (lazyMan == lazyMan2) {
    
    
			System.out.println("相等");
		}else {
    
    
			System.out.println("不相等");
		}
	}
}

在这里插入图片描述

2.2改良懒汉式单例 (三重检测)

package JUC;

import java.lang.reflect.Constructor;

/**   
 * 懒汉式单例 三重检测锁+volatile防止指令重排 
 */
public class SingletonLazyMan {
    
    

	private SingletonLazyMan(){
    
    
		//三重检测
		synchronized (SingletonLazyMan.class) {
    
    
			if (lazyMan!=null) {
    
    
				throw new RuntimeException("不要试图使用反射破坏异常");
			}
		}
		System.out.println(Thread.currentThread().getName());
	}
	
	private volatile static SingletonLazyMan lazyMan; 
	
	//双重检测锁 DCL懒汉式
	public static SingletonLazyMan getInstance() {
    
    
		if (lazyMan==null) {
    
    
			synchronized (SingletonLazyMan.class) {
    
    
				if (lazyMan==null) {
    
    
					lazyMan = new SingletonLazyMan();
					/**
					 * 不是原子性操作
					 * 1.分配内存空间
					 * 2.执行构造方法,初始化对象
					 * 3.把对象指向这个空间
					 * 
					 * 指令重排 123  
					 * 但是如果执行132 A
					 * 				B
					 */
				}
			}
		}
		return lazyMan; //此时SingletonLazyMan还没有完成构造
	}
	
	public static void main(String[] args) throws Exception, SecurityException {
    
    
		//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
		Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
		constructor.setAccessible(true);
		SingletonLazyMan lazyMan2 = constructor.newInstance();
		SingletonLazyMan lazyMan3 = constructor.newInstance();
		
		if (lazyMan == lazyMan2) {
    
    
			System.out.println("相等");
		}else {
    
    
			System.out.println("不相等");
		}
	}
}

在这里插入图片描述

2.3改良单例信号灯法

package JUC;

import java.lang.reflect.Constructor;

/**   
 * 懒汉式单例 三重检测锁+volatile防止指令重排 
 */
public class SingletonLazyMan {
    
    

	//信号灯
	private static boolean gouzi = false;
	
	private SingletonLazyMan(){
    
    
		//三重检测
		synchronized (SingletonLazyMan.class) {
    
    
			if (gouzi==false) {
    
    
				gouzi = true;
			} else {
    
    
				throw new RuntimeException("不要试图使用反射破坏异常");
			}
		}
		System.out.println(Thread.currentThread().getName());
	}
	
	private volatile static SingletonLazyMan lazyMan; 
	
	//双重检测锁 DCL懒汉式
	public static SingletonLazyMan getInstance() {
    
    
		if (lazyMan==null) {
    
    
			synchronized (SingletonLazyMan.class) {
    
    
				if (lazyMan==null) {
    
    
					lazyMan = new SingletonLazyMan();
					/**
					 * 不是原子性操作
					 * 1.分配内存空间
					 * 2.执行构造方法,初始化对象
					 * 3.把对象指向这个空间
					 * 
					 * 指令重排 123  
					 * 但是如果执行132 A
					 * 				B
					 */
				}
			}
		}
		return lazyMan; //此时SingletonLazyMan还没有完成构造
	}
	
	public static void main(String[] args) throws Exception, SecurityException {
    
    
		//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
		Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
		constructor.setAccessible(true);
		SingletonLazyMan lazyMan2 = constructor.newInstance();
		SingletonLazyMan lazyMan3 = constructor.newInstance();
		
		if (lazyMan == lazyMan2) {
    
    
			System.out.println("相等");
		}else {
    
    
			System.out.println("不相等");
		}
	}
}

在这里插入图片描述

2.4破坏单例信号灯

package JUC;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**   
 * 懒汉式单例 三重检测锁+volatile防止指令重排 
 */
public class SingletonLazyMan {
    
    

	//信号灯
	private static boolean gouzi = false;
	
	private SingletonLazyMan(){
    
    
		//三重检测
		synchronized (SingletonLazyMan.class) {
    
    
			if (gouzi==false) {
    
    
				gouzi = true;
			} else {
    
    
				throw new RuntimeException("不要试图使用反射破坏异常");
			}
		}
		System.out.println(Thread.currentThread().getName());
	}
	
	private volatile static SingletonLazyMan lazyMan; 
	
	//双重检测锁 DCL懒汉式
	public static SingletonLazyMan getInstance() {
    
    
		if (lazyMan==null) {
    
    
			synchronized (SingletonLazyMan.class) {
    
    
				if (lazyMan==null) {
    
    
					lazyMan = new SingletonLazyMan();
					/**
					 * 不是原子性操作
					 * 1.分配内存空间
					 * 2.执行构造方法,初始化对象
					 * 3.把对象指向这个空间
					 * 
					 * 指令重排 123  
					 * 但是如果执行132 A
					 * 				B
					 */
				}
			}
		}
		return lazyMan; //此时SingletonLazyMan还没有完成构造
	}
	
	public static void main(String[] args) throws Exception, SecurityException {
    
    
		//获取属性 改为private允许访问
		Field[] fields = SingletonLazyMan.class.getDeclaredFields();
		for (Field field : fields) {
    
    
			System.out.println(field.getName());
			field.setAccessible(true);
		}
		Field field = SingletonLazyMan.class.getDeclaredField("gouzi");
		
		//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
		Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
		constructor.setAccessible(true);
		SingletonLazyMan lazyMan2 = constructor.newInstance();

		//修改属性
		field.set(lazyMan2, false);
		
		SingletonLazyMan lazyMan3 = constructor.newInstance();
		
		if (lazyMan3 == lazyMan2) {
    
    
			System.out.println("相等");
		}else {
    
    
			System.out.println("不相等");
		}
	}
}

在这里插入图片描述

3.使用枚举 保护单例模式(防止反射攻击)

3.1为什么枚举可以保护 单例模式?

在这里插入图片描述

在这里插入图片描述

3.2 枚举创建单例

package JUC;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**   
 * 枚举懒汉式单例
 */
public enum EnumSingletonLazyMan {
    
    

	INSTANCE;
	
	public EnumSingletonLazyMan getInstance() {
    
    
		return INSTANCE;
	}
}

class TTTT{
    
    
	
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    
    
		EnumSingletonLazyMan e1 = EnumSingletonLazyMan.INSTANCE;
		
		Constructor<EnumSingletonLazyMan> constructor = EnumSingletonLazyMan.class.getDeclaredConstructor();
		constructor.setAccessible(true);
		
		//in thread "main" java.lang.NoSuchMethodException: JUC.EnumSingletonLazyMan.<init>()
		EnumSingletonLazyMan e2 = constructor.newInstance();
		
		if (e1 == e2) {
    
    
			System.out.println("相等");
		}else {
    
    
			System.out.println("不相等");
		}
	}
}

而得到的是这个
在这里插入图片描述
并非
在这里插入图片描述

3.3查看底层 反编译

找到.class目录下
在这里插入图片描述
进行反编译
在这里插入图片描述
也是有空参的,

3.4 使用jad.exe

在这里插入图片描述
在这里插入图片描述
看到最终源码 这里是有参构造器。

再次修改代码
在这里插入图片描述

4.总结

单例不安全,无论怎么修改都能被反射破解。
枚举创建单例安全,可以通过 专业编译器反编译出来,(枚举类)真实的源码。

猜你喜欢

转载自blog.csdn.net/jj89929665/article/details/113055008