五种单例模式
- 饿汉式
- 懒汉式
- 双重检测锁
- 静态内部类
- 枚举
- 使用反射和序列化破解单例模式
- 解决反射和序列化漏洞
1、饿汉式
描述:加载类时直接创建对象
特点:线程安全、效率高,不可延时加载
代码实现:
public class SingletonDemo {
/**
* 类初始化时立即加载
* 加载类时创建类 线程安全、没有同步(synchronized)调用的效率高
*/
private static SingletonDemo singleton = new SingletonDemo();
/**
* 私有化构造器
*/
private SingletonDemo(){
}
/**
* 创建公有获取类
* @return
*/
public static SingletonDemo getSingletonDemo(){
return singleton;
}
}
2、懒汉式
描述:加载类时不创建对象,在调用时创建
特点:线程安全、效率低,可延时加载
代码实现:
public class SingletonDemo2 {
/**
* 创建类对象 不初始化这个对象(延时加载,真正用时再创建)
*/
private static SingletonDemo2 singletonDemo;
/**
* 私有化构造器
*/
private SingletonDemo2() {
}
/**
* 公有获取类,使用同步(synchronized) 保证线程安全
* 因为使用synchronized 所以线程安全 但是效率较低
* @return
*/
public static synchronized SingletonDemo2 getSingleton(){
if(singletonDemo == null){
singletonDemo = new SingletonDemo2();
}
return singletonDemo;
}
}
3、双重检测锁
描述:在方法中使用synchronized使用
特点:线程安全、效率高,可延时加载;由于编译器优化以及jvm底层内部模型不建议使用
代码实现:
public class SingletonDemo3 {
/**
* 创建对象
*/
private static SingletonDemo3 singleton = null;
/**
* 私有化构造器
*/
private SingletonDemo3() {}
/**
* 创建公有获取类
*
* @return
*/
public static SingletonDemo3 getSingletonDemo() {
if (singleton == null) {
SingletonDemo3 singletonDemo3;
synchronized (SingletonDemo3.class) {
singletonDemo3 = singleton;
if(singletonDemo3 == null ){
synchronized (SingletonDemo3.class){
if (singletonDemo3 == null) {
singletonDemo3 = new SingletonDemo3();
}
}
singleton = singletonDemo3;
}
}
}
return singleton;
}
}
4、静态内部类
描述:在类中使用静态内部类
特点:线程安全、效率高;可延时加载
代码实现:
public class SingletonDemo4 {
/**
* 静态内部类
*/
private static class SingletonDemo4Instance{
private static final SingletonDemo4 singletonDemo4 = new SingletonDemo4();
}
private SingletonDemo4(){
}
public static SingletonDemo4 getInstance(){
return SingletonDemo4Instance.singletonDemo4;
}
}
5、枚举
描述:天然的单例模式
特点:线程安全,不可延时加载;天然避免反射和序列化的漏洞
代码实现:
public enum SingletonDemo5 {
//这个枚举元素本身就是一个单例
// 避免反射 反序列化的漏洞,但是没有延时加载
INSTANCE;
/**添加自己需要的方式*/
public void singletonDemo5(){
}
}
使用反射破解单例模式
代码实现:
public class Client2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
SingletonDemo2 singleton = SingletonDemo2.getSingleton();
SingletonDemo2 singleton1 = SingletonDemo2.getSingleton();
System.out.println(singleton);
System.out.println(singleton1);
//通过反射的方式直接调用私有构造器
Class<SingletonDemo2> aClass =(Class<SingletonDemo2>) Class.forName("com.singleton.SingletonDemo2");
Constructor<SingletonDemo2> declaredConstructor = aClass.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
SingletonDemo2 singletonDemo2 = declaredConstructor.newInstance();
SingletonDemo2 singletonDemo3 = declaredConstructor.newInstance();
System.out.println(singletonDemo2);
System.out.println(singletonDemo3);
}
}
使用序列化破解单例
注意:序列化需要被序列化的类实现 Serializable接口
public class Client2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
SingletonDemo2 singleton = SingletonDemo2.getSingleton();
SingletonDemo2 singleton1 = SingletonDemo2.getSingleton();
System.out.println(singleton);
System.out.println(singleton1);
//通过反序列化的方式构造多个对象
FileOutputStream fos = new FileOutputStream("d:/aaaa.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(singleton);
oos.close();
fos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/aaaa.txt"));
SingletonDemo2 o = (SingletonDemo2)ois.readObject();
System.out.println(o);
}
}
修复反射破解单例模式漏洞
在私有构造器的时候,加一层判断,如果不为空就直接抛出异常
/**
* 私有化构造器
*/
private SingletonDemo2() {
if(singletonDemo != null){
throw new RuntimeException();
}
}
修复反序列化破解单例模式漏洞
在被序列化的类中,写入 ReadResolve 当序列化时,返回当前类中已有的对象
/**反序列化时,如果定义了ReadResolve 则直接返回之前的对象*/
private Object readResolve()throws ObjectStreamException {
return singletonDemo;
}