- 饿汉式
- 懒汉式/Double check(双重检索)
- 静态内部类
- 枚举单例
饿汉式
private static final DispatchSingleton instence = new DispatchSingleton();
public static DispatchSingleton getInstence() {
return instence;
}
饿汉式是在jvm加载这个单例类的时候,就会初始化这个类中的实例,在使用单例中的实例时直接拿来使用就好,因为加载这个类的时候就已经完成初始化,并且由于是已经加载好的单例实例因此是线程安全的,并发获取的情况下不会有问题,是一种可投入使用的可靠单例。
优点:使用起来效率高、线程安全
缺点:由于jvm在加载单例类的时候需要初始化单例实例,因此在加载单例的时候针对jvm内存不够友好。
懒汉式
private static DispatchSingleton mSluggardInstence;
public static DispatchSingleton getSluggardInstence(){
if (mSluggardInstence==null){
mSluggardInstence=new DispatchSingleton();
}
return mSluggardInstence;
}
最简单的懒汉式,核心思想就是弥补饿汉式的缺点,在jvm加载单例类的时候不去初始化实例,而是在第一次获取实例的时候再去初始化实例。但是这样理论完美的单例在使用的时候有一个致命的缺点,在多线程使用的情况下,有时会出现不同线程从单例实例中获取不同的实体。针对多线程环境中并不可靠。
优点:针对jvm内存比较友好,实现了实例的懒加载。
缺点:多线程环境下不安全,会出现不同线程从单例实例中获取不同的实体的情况。
private static volatile DispatchSingleton mSluggardInstence;
public static DispatchSingleton getSluggardInstence() {
if (mSluggardInstence == null) {
synchronized (DispatchSingleton.class) {
if (mSluggardInstence == null) {
mSluggardInstence = new DispatchSingleton();
}
}
}
return mSluggardInstence;
}
synchronized
针对懒汉式的这种线程不安全的现:在单例初始化时,多线程存在创建多次实例的风险
“锁的粒度",锁的粒度: 粗和细加锁代码涉及到的范围,加锁代码的范围越大,认为锁的粒度越粗范围越小,则认为粒度越细
所以synchronized锁住获取实例的整个方法也可以解决问题,且在并发获取单例实例的时候会有性能问题。故此减小锁的粒度。
volatile
在于jdk1.5开始针对volatile进行了增强,因为Volatile会禁止指令重排序
静态内部类
private static class Holder{
private static DispatchSingleton singleton = new DispatchSingleton();
}
public static DispatchSingleton getHolderInstence() {
return Holder.singleton;
}
静态内部类的优点是:外部类加载时并不会立即加载内部类,内部类不被加载就不去初始化实例,因此实现了懒加载。当DispatchSingleton第一次被加载时,并不需要去加载内部类Holder,只有当getInstance()方法第一次被调用时,才会导致虚拟机加载Holer类菜会去初始化StaticSingle实例。这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
枚举单例
以上解决了效率或者懒加载以及线程安全的问题,但是它们都有两个共同的缺点: 序列化可能会破坏单例模式文章来源:https://www.toymoban.com/news/detail-722318.html
public enum DispatchSingle {
INSTANCE;
public void doSomething(){}
}
- 自由序列化
- 保证只有一个实例
- 线程安全
- 与静态内部类的区别
- 枚举单例为直接加载,静态内部类为懒加载
- 两者相比较,静态内部类比较节省资源开销
我们也可以像常规类一样编写enum类,为其添加变量和方法,访问方式也更简单,使用DispatchSingle .INSTANCE进行访问,这样也就避免调用getInstance方法,更重要的是使用枚举单例的写法,我们完全不用考虑序列化和反射的问题。枚举序列化是由jvm保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的。文章来源地址https://www.toymoban.com/news/detail-722318.html
到了这里,关于浅谈单例模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!