JAVA三种实现单例模式方法(一):懒汉式实现单例设计模式

package instance.lazy;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * 懒汉式单例
 * @author jingzi
 * 单例模式是最常用的设计模式,一个完美的单例需要做到哪些事呢?
 * 1、单例
 * 2、延迟加载
 * 3、线程安全
 * 4、没有性能问题
 * 5、防止序列化产生新对象
 * 6、防止反射攻击
 */
public class LazyType implements Serializable {
	
	private static final long serialVersionUID = 6427931149119200875L;
	/**
	 * 声明为volatile,保证多线程可见性、防止“instance = new LazyType()”指令重排序。
	 * 注:instance = new LazyType()是非原子性操作。
	 * instance = null:延迟加载。
	 */
	private volatile static LazyType instance = null;  
	
	private static boolean flag = false;
	
	private LazyType() {
		//防止反射攻击
		synchronized (LazyType.class) {
			if (false == flag) {
				flag = !flag;
			} else {
				//被反射攻击,抛出异常。
				throw new RuntimeException("Reflected attack!");
			}
		}
	}
	/**
	 * 执行两次校验:很有必要,这样可以保证线程安全。
	 * 当多线程调用时,如果多个线程同时执行完了第一次检查,其中一个进入他不代码块创建了实例,
	 * 后面的线程因第二次检查不会创建实例。
	 * @return
	 */
	public static LazyType getInstance() {
		if (null == instance) {//第一次检查
			synchronized (LazyType.class) {
				if (null == instance) {//第二次检查
					instance = new LazyType();
				}
			}
		}
		return instance;
	}
	
	/**
	 * 如果实现了Serializable, 必须重写这个方法,才能保证其反序列化依旧是单例,即防止序列化产生新对象。
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException {
		return instance;
	}
	
	/**
	 * 所执行的业务功能
	 */
	public void doSomethingElse() {
		
	}
}

测试,防止单例模式被java反射攻击:

package instance.lazy;
import java.lang.reflect.Constructor;
public class LazyTypeModifiedReflectAttack {
	public static void main(String[] args){
		try {
			Class<LazyType> classType = LazyType.class;
			Constructor<LazyType> c = classType.getDeclaredConstructor(null);
			c.setAccessible(true);
			LazyType e1 = (LazyType)c.newInstance();
			System.out.println("e1.hashCode():" + e1.hashCode());
			LazyType e2 = LazyType.getInstance();
			System.out.println("e2.hashCode():" + e2.hashCode());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

测试结果:

e1.hashCode():118352462
java.lang.RuntimeException: Reflected attack!
	at instance.lazy.LazyType.<init>(LazyType.java:36)
	at instance.lazy.LazyType.getInstance(LazyType.java:50)
	at instance.lazy.LazyTypeModifiedReflectAttack.main(LazyTypeModifiedReflectAttack.java:16)

这么写的具体原因可见:https://www.zhihu.com/question/29971746

此外,如何防止单例模式被JAVA反射攻击: https://blog.csdn.net/u013256816/article/details/50525335

参考内容:

https://blog.csdn.net/wzgiceman/article/details/51809985

https://blog.csdn.net/huangyuan_xuan/article/details/52193006

猜你喜欢

转载自blog.csdn.net/jingzi123456789/article/details/79978946