使用单例设计模式的类只有一个对象实例,基于此核心来编写代码。
- 懒汉式
public class LazySingleton {
private volatile static LazySingleton ton = null;
private LazySingleton(){}
public static LazySingleton lzTon() {
if(null == ton){
synchronized(LazySingleton.class){
if(null == ton)
ton = new LazySingleton();
}
}
return ton;
}
}
- 饿汉式
public class HungrySingleton {
private static final HungrySingleton ton = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton hslton(){
return ton;
}
}
- 内部静态类实现单例
public class SynthesisSingleton {
private static class Singleton{
public static final SynthesisSingleton ton = new SynthesisSingleton();
}
public SynthesisSingleton() {}
public static final SynthesisSingleton ssl(){
return Singleton.ton;
}
}
- 枚举单例
//枚举能规避序列化和线程安全的问题
public enum EnumSingleton {
TON;
public void fun(){
System.out.println("枚举单例");
}
}
上述单例基本达到了类只有一个对象实例
的核心目标,但也不是无懈可击,比如反射创建实例,反序列化得到的实例除了枚举单例都是新对象,下面以饿汉式和枚举单例参考。
public class MainTest {
/**
* 反射测试
* @throws Exception
*/
public static void reflectTest() throws Exception
{
{
HungrySingleton ton = HungrySingleton.hslton();
Class cla = HungrySingleton.class;
Constructor co = cla.getDeclaredConstructor(null);
co.setAccessible(true);
HungrySingleton ton1 = (HungrySingleton) co.newInstance(null);
System.out.println(ton);
System.out.println(ton1);
}
{
EnumSingleton ton = EnumSingleton.TON;
Class cla = EnumSingleton.class;
Constructor co = cla.getDeclaredConstructor(null);
co.setAccessible(true);
EnumSingleton ton1 = (EnumSingleton) co.newInstance(null);
System.out.println(ton);
System.out.println(ton1);
}
}
/**
* 序列化测试
*/
public static void serializ() throws Exception{
{
HungrySingleton ton = HungrySingleton.hslton();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/HungrySingleton.txt"));
oos.writeObject(ton);
oos.flush();
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/HungrySingleton.txt"));
HungrySingleton ton1 = (HungrySingleton) ois.readObject();
ois.close();
System.out.println(ton);
System.out.println(ton1);
}
{
EnumSingleton ton = EnumSingleton.TON;
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/EnumSingleton.txt"));
oos.writeObject(ton);
oos.flush();
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/EnumSingleton.txt"));
EnumSingleton ton1 = (EnumSingleton) ois.readObject();
ois.close();
System.out.println(ton);
System.out.println(ton1);
}
}
public static void main(String[] args) throws Exception{
serializ();
reflectTest();
}
}
最终结果是饿汉式序列化反序列化,反射前后对象不一致,而枚举单例则一致。很显然枚举单例经过了考验,那怎么避免饿汉式不能唯一实例
呢,最后的单例守护
文章里面提到了解决方案
public class HungrySingleton implements Serializable{
private static final long serialVersionUID = 1L;
private static final HungrySingleton ton = new HungrySingleton();
private HungrySingleton() {
//防止反射
if(null != ton){
throw new RuntimeException();
}
}
public static HungrySingleton hslton(){
return ton;
}
private Object readResolve(){
//防反序列化
return ton;
}
}
网友评论