各种单例的优缺点

    技术2022-07-10  150

    文章目录

    饿汉式优点缺点 懒汉式优点缺点 懒汉式加锁优点缺点 懒汉式双重检查锁优点缺点 静态内部类式优点 枚举类优点缺点 真的没有缺点吗?常用哪一种?

    饿汉式

    public class Singleton { private final static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } } 为什么叫这个名字?因为这个类太饿了,刚被加载就想实例化填饱肚子final的作用是instance被初始化后,instance不可被改变第一个static的作用是当类被加载时,instance就会被初始化

    优点

    线程安全

    缺点

    该类被加载就会初始化instance,如果没有被使用到,会浪费资源

    懒汉式

    public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 为什么叫这个名字?因为别的类不调用他的方法,他就不实例化,比较懒instance如果添加final关键字的话,instance必须在类被加载就初始化,而该方式是调用到getInstance方法才初始化,所以不能添加final关键字

    优点

    只有调用方法时,才会初始化

    缺点

    线程不安全

    懒汉式加锁

    public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 添加了synchronized关键字,当第一个线程进入该方法后,会持有该锁,此时另一个线程不能进入该方法,直到第一个线程完成方法,将锁释放,第二个线程才可以进入方法

    优点

    线程安全

    缺点

    当instance被初始化后,再有线程进入到getInstance方法时,锁就没有意义了,if (instance == null) 这行代码的后续就永远都不会执行,每次需要等待上一个线程返回instance后,再执行下一个线程。

    懒汉式双重检查锁

    public class Singleton { private volatitle static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } volatitle的作用synchronized的作用

    优点

    线程安全,解决了上一种方法的缺点

    缺点

    没有

    静态内部类式

    public class Singleton { private Singleton() { } private static class Inner { private final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return Inner.instance; } } 如何保证的线程安全:当线程A、B同时想要获取类的初始化锁,A先拿到后,完成初始化,释放锁,B获得初始化锁,发现对象已经初始化完毕,释放锁,直接返回已经初始化的对象

    优点

    代码简洁、线程安全

    枚举类

    public enum Singleton { INSTANCE; public void doSomething() { //doSomething } }

    优点

    代码简洁、线程安全

    缺点

    没有

    真的没有缺点吗?

    除了枚举类型,上述其他类型都可以通过反射来创建多个对象,但是还是可以更改构造方法去解决的。 private Singleton(){ if (instance != null){ throw new RuntimeException("已经实例化"); } } 除了枚举类型,上述其他类型如果实现了Serializable,那么都可以通过反序列化来出创建多个对象,解决方法:重写反序列化方法readResolve(),反序列化时直接返回已经实例化的对象 public Object readResolve() throws ObjectStreamException { return instance; }

    常用哪一种?

    懒汉式双重检查锁、静态内部类、枚举类

    Processed: 0.011, SQL: 9