单例模式
单例模式中,最常见的有饿汉式和懒汉式,以及双重检查模式 (DCL),静态内部类单例模式,枚举单例
//饿汉式(线程安全、立即加载)
public class singleton {
//立即加载
private static singleton instance=new singleton();
private singleton(){};
public static singleton getInstance()
{
return instance;
}
}
//懒汉式(线程安全、延迟加载)
public class singleton {
//延迟加载
private static singleton instance;
private singleton(){};
//synchronized是为了保证多线程访问下只创建一个实例
public static synchronized singleton getInstance()
{
if(instance==null)
instance=new singleton();
return instance;
}
}
//DCL
public class Singleton {
private volatile static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance== null) {
instance= new Singleton();
}
}
}
return singleton;
}
}
//静态内部类
public class Singleton {
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
//类加载时不会加载内部静态类,因此是延迟加载
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
//枚举单例
public enum Singleton {
INSTANCE;
public void doSomeThing() {
}
}
注意:单例模式(枚举除外)可以被反射机制破解
public class Main {
public static void main(String[] args) throws Exception {
singleton s1=singleton.getInstance();
singleton s2=singleton.getInstance();
System.out.println(s1==s2);//true
Class<singleton> clazz= (Class<singleton>) Class.forName("zdy.singleton");
Constructor<singleton> constructor=clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);//跳过权限访问
singleton s3=constructor.newInstance();
singleton s4=constructor.newInstance();
System.out.println(s3==s4);//false
}
}
解决方案:在构造函数中进行检测
private singleton() throws Exception {
if(instance!=null)
throw new Exception("illegal access");
};
单例模式也能被反序列化破解,前提是单例实现了序列化,即implements Serializable
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/a.text"));
oos.writeObject(s1);;
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.text"));
SingletonDemo2 s3 = (SingletonDemo2) ois.readObject();
解决方案:在单例中添加如下方法,返回原对象
public Object readResolve(){
return instance;
}