单例模式
保证了一个类只有一个实例,并提供了一个获取它实例的方法
几种写法
饿汉模式
-
代码如下
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
- 该实例 是类的成员之一,在类加载的时候就初始化好了
- 类的加载比较慢,但是获取类的实例是很快的。
- 这种基于类加载机制,避免了多线程同步问题。
- 因为是在类加载的时候就初始化好了,如果从来没有使用过久浪费了内存。
-
懒汉模式(线程不安全的)
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
- 第一次加载的时候需要实例化,反应慢些
- 是线程不安全的,在多线程下不能安全工作。
-
懒汉模式(线程安全的)
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
- 保证了多线程下的安全性
- 每次调用都需要进行同步,造成不必要的同步开销。
-
双重检查模式(DCL)
public class Singleton { private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class){ if (instance == null){ instance = new Singleton(); } } } return instance; } }
- 第一次非空判断,是为了不必要的同步
- 第二次在为null的情况下创建实例。
- 建议使用静态内部类单例模式
-
静态内部类单例模式
public class Singleton { private Singleton() { } public static Singleton getInstance() { return SingleHolder.mInstance; } private static class SingleHolder { private static final Singleton mInstance = new Singleton(); } }
- 静态内部类不会随着外部类的加载被立即加载。所以mInstance就不会被初始化,不占用内存。
- 当第一次调用getInstance方法的时候,虚拟机才会去加载SingleHolder。
- 当多个线程同时去初始化一个类的,那么有且只有一个线程去执行初始化,其他都将会被阻塞等待,直到初始化结束。
- 所以就是线程安全的。
- 静态内部类并不是一个非常完美的,它不能够传递参数,比如我们需要的Context,所以在DCL和它之间根据不同的业务场景,可以选择一下。
-
枚举单例
public enum Singleton { INSTANCE; public void method(){ } }
- 是线程安全的
总结
- 单利模式,都会显示的写出构造方法,并使用private关键字修饰,保证力一个应用中只能产生一个实例。
优点
- 单利模式在内存中一个实例,那么就不会占用很多的内存。
- 因为只存在一个实例,可以有效避免减少系统的性能开销,比如一个单利类中有很多读取配置文件啊,和其他类产生依赖,那么我们可以考虑使用单利模式,真样创建一个就永久保留在内存中,不会因为重复创建和销毁而对系统增加压力。
- 同样,如果一个单利类中有很O操作,比如写文件的动作,一个单利类能保证避免对同一个资源文件的同时写操作,避免对资源的浪费了。
缺点
- 单利类不像其他设计模式那样,有接口,有实现类,它没有,这样就导致它的灵活性就不高,扩展性不高
- 单利类为什么不能用接口呢?
- 对于单利类来说,我们最终的目的是自行化创建类的实例,对于接口或者抽象类来说本省就不能被实例化,并且这对于创建类实例来说也没有意义。
- 单利类可以去实现接口或者被继承,可以在业务中自由选择嘛。
网友评论