单例模式

单例模式特点

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

  • windows中的任务管理器

  • 操作系统的文件系统,一个操作系统只能有一个文件系统

  • servlet编程中,每个servlet也是单例

  • SpringMVC中,控制对象也是单例

  • Spring中的bean

单例模式_第1张图片
单例模式类图

单例模式分类

饿汉式

特点:减少系统开销

    public class SingletonDemo {
        //类初始化的时候立即加载(没有延时加载的优势),由于加载类的时候天热的线程安全
        private static final SingletonDemo singleDemo = new SingletonDemo();
        //私有化构造器
        private SingletonDemo() {
        }
        //方法没有同步,调用效率高
        public static SingletonDemo getInstance(){
            return singleDemo;
        }
    }

懒汉式

懒汉式普通实现

特点:真正用的时候加载,资源的利用率高,但是每次调用的时候需要同步,并发下效率低

public class SingletonDemo1 {
    //调用的时候加载
    private static SingletonDemo1 instance = null;
    //私有化构造器
    private SingletonDemo1() {
    }
    //方法同步,调用效率低
    //为什么加锁:多线程下,不加锁会产生多个实例
    public static synchronized SingletonDemo1 getInstance() {
        if (instance == null) {
            instance = new SingletonDemo1();
        }
        return instance;
    }
}

懒汉式静态内部类实现

特点:

  • 外部没有static属性不会饿汉式那样立即加载对象

  • 真正调用getInstance()时,才会加载静态内部类.类加载时是线程安全的,static final保证内存中实例唯一

  • 兼具并发高效和延时加载的优势

public class SingletonDemo2 {
    private static class singletonClass {
        private static final SingletonDemo2 instance = new SingletonDemo2();
    }
    public static SingletonDemo2 getInstance() {
        return singletonClass.instance;
    }
    private SingletonDemo2() {
    }
}

懒汉式其他实现

  • 双重检测锁式(由于jvm底层内部模型原因,偶尔会出问题,不建立使用)

  • 枚举单例(线程安全,调用效率高,不能延时加载)

反射和反序列化漏洞

反射漏洞

反射可以破解单例(不包含枚举式)实现方式!(可以在构造方法中手动抛出异常控制)

//测试
public class Client {
    public static void main(String[] args) throws Exception {
        SingletonDemo2 demo = SingletonDemo2.getInstance();
        SingletonDemo2 demo1 = SingletonDemo2.getInstance();
        System.out.println(demo);
        System.out.println(demo1);


        Class singletonDemo2Class = (Class) Class.forName("singleton.SingletonDemo2");
        Constructor constructor = singletonDemo2Class.getDeclaredConstructor();
        constructor.setAccessible(true);
        SingletonDemo2 demo2 = constructor.newInstance();
        SingletonDemo2 demo3 = constructor.newInstance();
        System.out.println(demo2);
        System.out.println(demo3);
    }
}
//SingletonDemo2类的构造方法修改为
//私有化构造器
private SingletonDemo2() {
    if (singletonClass.instance != null) {
    throw  new RuntimeException();
    }
}

反序列化

反序列化可以破解单例(不包含枚举式)实现方式!(可以添加readResolve()方法)

public class Client {
    public static void main(String[] args) throws Exception {
        SingletonDemo2 demo = SingletonDemo2.getInstance();
        SingletonDemo2 demo1 = SingletonDemo2.getInstance();
        System.out.println(demo);
        System.out.println(demo1);

        FileOutputStream fileOutputStream = new FileOutputStream("/Users/wjk/Desktop/a.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(demo);
        objectOutputStream.close();;
        fileOutputStream.close();


        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/wjk/Desktop/a.txt"));
        SingletonDemo2 singletonDemo2 =(SingletonDemo2) objectInputStream.readObject();
        System.out.println(singletonDemo2);
    }
}

//SingletonDemo2类实现序列化添加readResolve()
private Object readResolve() throws ObjectStreamException{
        return singletonClass.instance;
    }
}

你可能感兴趣的:(单例模式)