单例模式
保证在一个JVM(虚拟机)中,该对象只有一个实例存在,可以存在多个对象,但是对象的本质相同
单例应该具备:
* 1线程的安全
* 2调用效率高
* 3懒加载
First 饿汉式实现 (线程安全,调用效率高,不能延时加载)
public class Demo1
{
//构造方法私有
private Demo1()
{
}
//饿汉式单例实现 提前实例化
private static final Demo1 A=new Demo1();
//* 静态工厂方式
public static Demo1 getInstance()// 相当于一个方法
{
return A;
}
}
Second 懒汉式 (线程安全,调用效率低,可以延时加载)
public class Demo2 {
private Demo2()
{
}
/*
*懒汉式单例实现
* 在第一次调用时实例化
* 需要使用线程同步,并发的效率低
* 实现了延时加载,用的时候加载
*/
private static Demo2 A;
public static synchronized Demo2 getInstance()
//synchronized 线程同步,同一时刻,只有一个线程进入这个方法
{
if(A==null)
{
//第一次调用的时候实例化
System.out.println("第一次调用的时候实例化");
A=new Demo2();
}
return A;
}
}
Third 双重检测锁模式 (JVM底层问题,不建议使用)
/*由于编译器优化原因和JVM底层内部模型的原因,这个是最难用的,容易崩溃*/
public class Demo3
{
private Demo3(){};
private static Demo3 A=null;
public static Demo3 getInstance()
{
if(A==null)
{
Demo3 sc=null;
synchronized (Demo3.class)
{
sc=A;
if(sc==null)
{
synchronized (Demo3.class)
{
if(sc==null)
{
sc=new Demo3();
}
}
A=sc;
}
}
}
return A;
}
}
Fourth 静态内部类 (线程安全,调用效率高,可以延时加载)
//几乎就是最完美的方法 public class Demo4 { private static class SingClassinstance { private static final Demo4 Instance= new Demo4(); } public static Demo4 getInstance() { return SingClassinstance.Instance; } private Demo4(){}; }
Fifth 枚举 (线程安全 调用效率最高 不能延时加载 在底层上可以防止反射和反序列漏洞)
//枚举类 没有延时加载 //避免反射和反序列化的漏洞 //本身就是单例 public enum Demo5 { A; }
总结与一下效率问题
单纯在时间来看
饿汉式<静态内部类<枚举式<双重检测锁式<懒汉式
------------------------------------------------------------- 下面的东西完全可以不看,除非开发底层的项目------------------
Demo2P 防止反射
public class Demo2P
{
private Demo2P()
{
if (A!=null)
{
throw new RuntimeException("防止反射已开启");
}
}
private static Demo2P A;
public static synchronized Demo2P getInstance()
//synchronized 线程同步,同一时刻,只有一个线程进入这个方法
{
if(A==null)
{
//第一次调用的时候实例化
System.out.println("第一次调用的时候实例化");
A=new Demo2P();
}
return A;
}
}
Demo2S 防止反序列
public class Demo2S { private Demo2S() { } private static Demo2S A; public static synchronized Demo2S getInstance() //synchronized 线程同步,同一时刻,只有一个线程进入这个方法 { if(A==null) { //第一次调用的时候实例化 System.out.println("第一次调用的时候实例化"); A=new Demo2S(); } return A; } //反序列化时如果定义了如下方法,则直接返回指定的对象, 不需要单独的再创建对象 private Object readResolve () throws Exception { return A; } }
反射的方法破坏单例模式
public class Test_FanShe
{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
{
Class<Demo2> clazz= (Class<Demo2>) Class.forName("设计模式.创建者模式.单例模式.Demo2");
Constructor<Demo2> c =clazz.getDeclaredConstructor(null);
//跳过权限的检查
c.setAccessible(true);
Demo2 S3= c.newInstance();
Demo2 S4=c.newInstance();
System.out.println(S3);
System.out.println(S4);
//现在可以被反射,导致单例模式失败
//Demo2P可以防止反射
Class<Demo2P> clazz2= (Class<Demo2P>) Class.forName("设计模式.创建者模式.单例模式.Demo2P");
Constructor<Demo2> c2 =clazz.getDeclaredConstructor(null);
Demo2 S5= c2.newInstance();
Demo2 S6=c2.newInstance();
System.out.println(S5);
System.out.println(S6);
}
}
反序列的方法破坏单例模式
public class Test_xuliehua
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
Demo2F S1=Demo2F.getInstance();
Demo2F S2=Demo2F.getInstance();
FileOutputStream fos= new FileOutputStream("fxlh.txt");
ObjectOutputStream oos= new ObjectOutputStream(fos);
oos.writeObject(S1);
fos.close();
oos.close();
// 取出
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("fxlh.txt"));
Demo2F S3=(Demo2F) ois.readObject();
System.out.println(S1);
System.out.println(S2);
System.out.println(S3);
}
}