单例模式的几种设计方法

package test1;
//饿汉模式
/*public class SingleDemo {
	private static SingleDemo instance = new SingleDemo();
	private SingleDemo(){}
	public static SingleDemo getinstance(){
		return instance;
	}
}*/

//懒汉模式
/*public class SingleDemo{
	private static SingleDemo instance=null;
	private SingleDemo(){}
	public static SingleDemo getinstance(){
		if(instance==null)
			instance = new SingleDemo();
		return instance;
	}
}*/

//懒汉加锁-线程安全
/*public class SingleDemo{
	private static SingleDemo instance=null;
	private SingleDemo(){}
	public static synchronized SingleDemo getinstance(){
		if(instance==null)
			instance=new SingleDemo();
		return instance;
	}
}*/
//双重校验+锁机制
/*加锁的懒汉模式看起来即解决了线程并发问题,又实现了延迟加载,然而它存在着性能问题,
依然不够完美。synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),
累积的性能损耗就比较大了。因此就有了双重校验锁,先看下它的实现代码。*/
/*public class SingleDemo{
	private static SingleDemo instance=null;
	private SingleDemo(){}
	public static SingleDemo getinstance(){
		if(instance==null)
			synchronized(SingleDemo.class){//这个括号必须加
				if(instance==null)
					instance=new SingleDemo();
			}
		return instance;	
	}
}*/
/*由于指令重排优化的存在,导致初始化Singleton和将对象地址赋给instance字段的顺序是不确定的。
在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。
此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。
若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错。
*/
//使用 volatile 关键字保证读之前,对象被初始化
/*public class SingleDemo{
	private static volatile SingleDemo instance=null;
	private SingleDemo(){}
	public static SingleDemo getinstance(){
		if(instance==null)
			synchronized(SingleDemo.class){//这个括号必须加
				if(instance==null)
					instance=new SingleDemo();
			}
		return instance;	
	}
}*/
//静态内部类
public class SingleDemo{
	private static class SingleHolder{
		public static SingleDemo instance = new SingleDemo();
	}
	private SingleDemo(){}
	public static SingleDemo getinstance(){
		return SingleHolder.instance;
	}
}

单例模式是 保证系统中只有一个本类的实例,那么如果之后还想用这个类多造些实例呢?

1.单例模式的良性破坏:

让单例模式的类 implements Cloneable,@override clone 方法。

2.恶意破坏 ---反射 

何止创建一个实例,反射一个类都易如反掌。main方法中:setAccessible(true)的方法是java跳过检测语法,这是不合理的,

解决方法,在类里重新定义一个内部类,在构造方法中判断,如果被多次调用,直接抛出异常,使构造函数终止。

Constructor constructor = SingleTest.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingleTest s3 = (SingleTest) constructor.newInstance();

3.序列化

通过对Singleton的序列化与反序列化得到的对象是一个新的对象,这就破坏了Singleton的单例性。 

防止被破坏的思路可以类似,修改私有的构造方法 抛出异常

private static SingletonDemo6 instance;
	
	private SingletonDemo6() {
		// 防止反射获取多个对象的漏洞
		if (null != instance) {
			throw new RuntimeException();
		}
	}

猜你喜欢

转载自blog.csdn.net/qq_33608638/article/details/79972391