各种单例的优缺点

文章目录

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

饿汉式

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;
    }

常用哪一种?

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

你可能感兴趣的:(设计模式,java,设计模式)