设计模式(三)Singleton Pattern单例设计模式
1.饿汉式
public class SingletonDemo { private static SingletonDemo s=new SingletonDemo(); private SingletonDemo() {} public static SingletonDemo getInstance() { return s; } }
public class Test { public static void main(String[] args) { SingletonDemo s=SingletonDemo.getInstance(); } }
步骤: 1.new出静态对象
2.构造方法私有化
3.写一个方法返回静态对象
说明: 1.由于加载类时天然的是线程安全
2.方法没有同步,调用效率高
3.立即加载,没有延时加载的优势
2.懒汉式(延时加载)
public class SingletonDemo { private static SingletonDemo s; private SingletonDemo() {} public static synchronized SingletonDemo getInstance() { if(s==null) s=new SingletonDemo(); return s; } }
public class Test { public static void main(String[] args) { SingletonDemo s=SingletonDemo.getInstance(); } }
优势: 1.修改点同步,在线程高并发时,能够保证安全性
2.延时new出类,能够做到用的时候去new它
3.双重检测锁实现
由于java编译器优化的原因和JVM底层内部模型的原因,偶尔会出一点问题,不建议使用
这个模式将同步内容下方到if内部,提高了执行效率,不必每次获取对象时都进行同步,至于一次才同步
public class SingletonDemo { private static SingletonDemo instance; private SingletonDemo() {} public static SingletonDemo getInstance() { if(instance==null) { SiSingletonDemo sc; synchronized (SingletonDemo.class) { sc=instance; } if(sc==null) { synchronized (SingletonDemo.class) { if(sc==null) { sc=new SingletonDemo(); } } instance=sc; } } return instance; } }
4.静态内部类(懒加载)
public class SingletonDemo { private static class SingletonClassInstance{ private static final SingletonDemo instance=new SingletonDemo(); } private SingletonDemo() {} public static SingletonDemo getInstance() { return SingletonDemo.getInstance(); } }
5.枚举单例模式
public enum SingletonDemo { INSTANCE; //枚举本来就是单例对象 //避免了反序列和反射的调用 //缺点,没有延时调用 public void singletonOperation() { } }
6.统一建模语言UML(unified modeling language)
可以拖动类做uml图
利用反射破解单例设计模式(不包含枚举单例,因为枚举型单例是利用JVM底层实现的单例设计模式)
public class TestSingleObject { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { SingleObject s1=SingleObject.getInstance(); SingleObject s2=SingleObject.getInstance(); Class<SingleObject> clazz=(Class<SingleObject>) Class.forName("com.littlepage.singletonPattern.SingleObject"); Constructor<SingleObject> c=clazz.getDeclaredConstructor(null); c.setAccessible(true);//跳过检测 SingleObject s3=c.newInstance(); SingleObject s4=c.newInstance(); System.out.println(s1); System.out.println(s2); System.out.println(s3); System.out.println(s4); } }
解决方法,在空参构造中加入
if(SingletonObject!=null){
throw new runtimeExpection();
}
进行调用时抛出异常就行
//举例 public class SingleObject { public static class SingleObjectInstance{ public static final SingleObject instance=new SingleObject(); } private SingleObject(){ if(SingleObjectInstance.instance!=null){ try { throw new Exception("运行时异常"); } catch (Exception e) { e.printStackTrace(); System.exit(0); } } } public static SingleObject getInstance(){ return SingleObjectInstance.instance; } }
利用序列化反序列化进行破解
public class TestSingleObject { public static void main(String[] args) throws IOException, ClassNotFoundException { SingleObject s1=SingleObject.getInstance(); System.out.println(s1); FileOutputStream fops=new FileOutputStream("d:/a.txt"); ObjectOutputStream oops=new ObjectOutputStream(fops); oops.writeObject(s1); oops.close(); ObjectInputStream ois =new ObjectInputStream(new FileInputStream("d:/a.txt")); SingleObject s2=(SingleObject) ois.readObject(); System.out.println(s2); ois.close(); } }
解决办法:
private Object resdResolve() throws ObjectStreamException{ return SingleObjectInstance.instance; }
添加该代码,可以使读取Object时直接返回已经存在的实例