1.饿汉式(特点:调用效率高,不能延时加载)
//饿汉式
public class SingletonDemo1 {
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1(){}
public static SingletonDemo1 getInstance(){
return instance;
}
}
2.懒汉式(特点:可延时加载,调用效率低)
//懒汉式
public class SingletonDemo2{
private static SingletonDemo2 instance;
private SingletonDemo2(){}
public static synchronized SingletonDemo2 getInstance(){
if(instance==null){
instance = new SingletonDemo2();
}
return instance;
}
}
3.双重检测式(由于JVM底层原因,不可靠,避免使用)
//双重检测锁
public class SingletonDemo3{
private static SingletonDemo3 instance;
private SingletonDemo3(){}
public static SingletonDemo3 getInstance(){
if(instance==null){
synchronized(SingletonDemo3.class){
if(instance==null){
instance = new SingletonDemo3();
}
}
}
return instance;
}
}
4.静态内部类式(特点:调用效率高且可以延时加载)
//静态内部类实现方式
public class SingletonDemo4{
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){}
public static SingletonDemo4 getInstance(){
return SingletonClassInstance.instance;
}
}
5.枚举式(特点:调用效率高,不能延时加载,天然防止反射和反序列化漏洞)
//枚举式
public enum SingletonDemo5{
INSTANCE;
public void SingletonOperation(){
}
}
对于1--4,可利用反射和反序列化破解单列,以饿汉式为例
package cn.baokx.gof23;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
//利用反射破解单例
Class<SingletonDemo1> clazz = (Class<SingletonDemo1>)Class.forName("cn.baokx.gof23.SingletonDemo1");
Constructor<SingletonDemo1> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
SingletonDemo1 s1 = c.newInstance();
SingletonDemo1 s2 = c.newInstance();
System.out.println(s1==s2);
}
}
解决方案:
//饿汉式
public class SingletonDemo1 {
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1(){
if(null!=instance){
throw new RuntimeException();
}
}
public static SingletonDemo1 getInstance(){
return instance;
}
}
package cn.baokx.gof23;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
//利用序列化破解单例
SingletonDemo1 s1 = SingletonDemo1.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/obj.data"));
oos.writeObject(s1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/obj.data"));
SingletonDemo1 s2 = (SingletonDemo1)ois.readObject();
ois.close();
System.out.println(s1==s2);
}
}
解决方案:
//饿汉式
public class SingletonDemo1 implements Serializable{
private static SingletonDemo1 instance = new SingletonDemo1();
//防反射破解单例
private SingletonDemo1(){
if(null!=instance){
throw new RuntimeException();
}
}
public static SingletonDemo1 getInstance(){
return instance;
}
//防反序列化破解单例
private Object readResolve() throws ObjectStreamException {
return instance;
}
}