一、核心作用
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点(public开发公共方法)。
二、饿汉式实现
类初始化时,立即加载这个对象,也就没有了延时加载;天然的线程安全。
package pattern.singleton;
/**
* 饿汉式单例模式
* @author zhou
*
*/
public class SingletonDemo1 {
//类初始化时,立即加载这个对象;天然的线程安全
private static SingletonDemo1 s = new SingletonDemo1();
private SingletonDemo1() {}
//方法没有同步,调用效率高
public static SingletonDemo1 getInstance() {
return s;
}
}
三、懒汉式实现
加synchronized关键字,同步机制,可以避免在并发量高的情况下创建多个对象。
类初始化时,不初始化这个对象,延时加载;方法同步,调用效率低。
package pattern.singleton;
public class SingletonDemo2 {
private static SingletonDemo2 s;
private SingletonDemo2() {}
public static synchronized SingletonDemo2 getInstance() {
if(s == null) {
s = new SingletonDemo2();
}
return s;
}
}
四、静态内部类式
线程安全, 调用效率高,实现了延时加载。
package pattern.singleton;
public class SingletonDemo3 {
static class SingletonDemoInstance{
private static final SingletonDemo3 singleton = new SingletonDemo3();
}
private SingletonDemo3() {}
public static SingletonDemo3 getInstance() {
return SingletonDemoInstance.singleton;
}
}
五、枚举式
可以防止反射和反序列化漏洞
package pattern.singleton;
public enum SingletonDemo4 {
//这个枚举元素,本身就是单例;可以避免反射和反序列化的漏洞;没有延时加载
INSTANCE;
}
六、总结
七、
1、通过反射破解跳过单例
package pattern.singleton;
import java.lang.reflect.Constructor;
public class Client {
public static void main(String[] args)throws Exception {
SingletonDemo3 singleton = SingletonDemo3.getInstance();
SingletonDemo3 singleton2 = SingletonDemo3.getInstance();
System.out.println(singleton == singleton2);
Class<SingletonDemo3> cls = (Class<SingletonDemo3>) Class.forName("pattern.singleton.SingletonDemo3");
Constructor<SingletonDemo3> constructor = cls.getDeclaredConstructor(null);
constructor.setAccessible(true);
SingletonDemo3 s3 = constructor.newInstance();
SingletonDemo3 s4 = constructor.newInstance();
System.out.println(s3);
System.out.println(s4);
/*
* System.out.println(s3.getInstance()); System.out.println(s4.getInstance());
*/
}
}
2、通过序列化和反序列化破解单例
需要实现 implements Serializable 接口
结果: