package singleton;
/**
* 单例模式 - 饿汉式
* 特点: 立即加载,调用时效率高
* 原理: 声明为static的变量在类加载时即初始化,jvm加载类不会发生并发问题
* 缺点: 如果不需要用到该类,将造成资源浪费
*/
public class SingletonDemo1 {
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1() {}
public static SingletonDemo1 getInstance() {
return instance;
}
}
package singleton;
/**
* 单例模式 - 懒汉式
* 特点: 延迟加载,调用时效率低
* 原理: 变量不是在初始化时赋值,而是在第一次调用时赋值
* 缺点: 每次方法的调用都需要同步,效率较低
*/
public class SingletonDemo2 {
private static SingletonDemo2 instance;
private SingletonDemo2(){}
public static synchronized SingletonDemo2 getInstance() {
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
package singleton;
/**
* 单例模式 - 双重检测锁
* 特点: 延迟加载,调用时效率一般
* 原理: 与饿汉式相似,只不过由synchronized块结合volatile变量进行2次检查同步
* 缺点: 不稳定,有时会出问题
*/
public class SingletonDemo3 {
private volatile static SingletonDemo3 instance;
private SingletonDemo3() {
}
public static SingletonDemo3 getInstance() {
if (instance == null) {
synchronized (SingletonDemo3.class) {
if (instance == null) {
instance = new SingletonDemo3();
}
}
}
return instance;
}
}
package singleton;
/**
* 单例模式 - 静态内部类
* 特点: 延迟加载,调用时效率高
* 原理: 静态内部类只有在调用时才初始化,变量声明为private static final保证不变性与唯一性
* 缺点:
*/
public class SingletonDemo4 {
private static class SingletonInstance{
private static SingletonDemo4 INSTANCE = new SingletonDemo4();
}
private SingletonDemo4(){}
public static SingletonDemo4 getInstance() {
return SingletonInstance.INSTANCE;
}
}
package singleton;
/**
* 单例模式 - 枚举类
* 特点: 立即加载,调用时效率高,不会被反射或反序列化
* 原理: 枚举类本身是单例的
* 缺点: 不能延迟加载
*/
public enum SingletonDemo5 {
INSTANCE;
}
package singleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
/**
* 测试5个单例模式的实现方法
* 反射与反序列化漏洞及解决
*
*/
public class Test {
public static void main(String[] args) {
Test test = new Test();
System.out.println("正常获取实例,判断与正常获得的是否同一个实例:");
test.test1();
System.out.println("反射获取实例,判断与正常获得的是否同一个实例:");
test.test2();
System.out.println("反序列化获取实例,判断与正常获得的是否同一个实例:");
test.test3();
}
public void test1() {// 正常
System.out.println("demo1--" + (SingletonDemo1.getInstance() == SingletonDemo1.getInstance()));
System.out.println("demo2--" + (SingletonDemo2.getInstance() == SingletonDemo2.getInstance()));
System.out.println("demo3--" + (SingletonDemo3.getInstance() == SingletonDemo3.getInstance()));
System.out.println("demo4--" + (SingletonDemo4.getInstance() == SingletonDemo4.getInstance()));
System.out.println("demo5--" + (SingletonDemo5.INSTANCE == SingletonDemo5.INSTANCE));
}
public void test2() {// 反射
try {
test2_2("singleton.SingletonDemo1");
test2_2("singleton.SingletonDemo2");
test2_2("singleton.SingletonDemo3");
test2_2("singleton.SingletonDemo4");
test2_2("singleton.SingletonDemo5");
} catch (Exception e) {
System.out.println(e.getMessage()+e.getClass());
}
}
public void test2_2(String className) throws Exception {// 反射获取构造器,生成实例
Class c = (Class) Class.forName(className);
Constructor constructor = c.getDeclaredConstructor(null);// 空构造方法
constructor.setAccessible(true);// 忽略访问权限(因构造方法被声明为private)
System.out.println(className + "--" +(constructor.newInstance() == constructor.newInstance()));
}
public void test3() {// 反序列化
SingletonDemo demo = (SingletonDemo) test3_3(SingletonDemo.getInstance());
System.out.println("demo--" + (demo == SingletonDemo.getInstance()));
SingletonDemo5 demo5 = (SingletonDemo5) test3_3(SingletonDemo5.INSTANCE);
System.out.println("demo5--" + (demo5 == SingletonDemo5.INSTANCE));
}
public Object test3_3(Object obj) {// 序列化,反序列化
Object resultObj = null;
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/test.txt"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/test.txt"));)
{
oos.writeObject(obj);
resultObj = ois.readObject();
}catch (Exception e) {
e.printStackTrace();
}
return resultObj;
}
static class SingletonDemo implements Serializable{// 饿汉式
private static SingletonDemo instance = new SingletonDemo();
private SingletonDemo() {}
public static SingletonDemo getInstance() {
return instance;
}
/**
* 防止反序列化时生成新的实例(手动重写readResolve方法)
* @return 执行反序列化时得到的实例
*/
// private Object readResolve() {
// return instance;
// }
}
}