美文网首页
设计模式:单例

设计模式:单例

作者: _爱笑的eyes | 来源:发表于2019-06-16 20:31 被阅读0次

    概念:单例就是一种对象创建模式,它用于产生一个对象的具体实例,他可以确保系统中一个类只产生一个实例。

    在Java中单例有两个好处:

    1.对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。

    2.由于new对象操作的次数减少,因而对系统内存的试用频率也会降低这将减轻GC压力,缩短GC停顿时间。

    单例的六种写法和各自的特点:

    饿汉/懒汉/懒汉线程安全/DCL/静态内部类/枚举

    饿汉:

    1.有一个private构造函数;2.有一个mHungurySingleton变量是static的,同时他的getHungurySingleton方法也是静态的,说明是向外部提供单例的一种方法。

    饿汉的缺点就是无法对mHungurySingleton对象做延时加载。因为instance会初始化很多的数据,所以导致他的static变量会被重复的加载。

    优化方式:为了延时加载需要进行优化,优化的目标就是懒汉模式。

    懒汉:

    首先会把他的静态成员变量设为null,不用做初始化就可以,确保系统启动的时候没有额外的负担,这也是性能优化点之一。

    然后在getInstance方法中判断当前单例的instance是否存在,存在的话就返回,不存在就重新创建单例。

    这里就实现了懒汉的单例,但是在多线程并发这样的实现是无法保证实例是唯一的,就是说在多线程并发情况下,单例懒汉是完全失效的。导致失效最主要的原因就是getInstance方法不是同步的。

    懒汉的缺点就是:在多线程并发下这样的实现是无法保证实例是唯一的

    优化就是做一个懒汉线程安全的单例模式。

    懒汉线程安全模式有两种:

    一种在方法名中设置synchronized关键字,这样就保证了如果出现非线程安全问题,由于多个线程会同时进去getInstance方法,synchronized保证只有一个线程可以进入方法,这样就能让懒汉线程安全了。

    同步代码块中实现,不在方法中执行,用LazySafetySingleton.class这个对象来保证线程安全。

    懒汉线程安全相对于懒汉模式是安全的,但是他有性能效率上的问题。如何解决?就用DCL,就是双重检查锁机制。

    DCL双重检查锁机制

    双重检查锁机制就是使用同步块加载的方法。因为他有两次检查instance是否为空,一次在同步代码块之外,一次在同步代码块之内。为什么在同步代码块之内还要检查instance是否为空呢?因为可能会有多个线程一起进入同步块外围,如果不在同步块中进行二次检验的话就会生成多个实例了,那就是懒汉模式的一些缺点。

    new DclSingleton这个操作也会存在不安全问题,也会报错,解决办法就是将instance变量设为volatil就可以了,volatil这个关键字是可见性,也就是他能保证线程保存在本地不会有instance副本,而每次都回到内存中去读取。

    DCL解决了懒汉的线程安全问题。也有缺点就是JVM的即时编译器中存在指令重排序的优化,把instance的变量设为volatil就可以解决这个问题。但是更好的优化就是静态内部类和枚举。

    枚举

    枚举最大的特点就是写法简单,线程安全。线程安全是有条件的,如果不写实例方法的话,默认情况下枚举的实例是线程安全的,如果要自己添加变量和实例方法一定要注意线程安全。同时枚举在性能上也有更大的优势。

    总结:

    饿汉:无法对instance实例进行延时加载

    懒汉:多线程并发情况下无法保证实例的唯一性

    懒汉线程安全:使用synchronized导致性能缺陷。synchronized锁住了方法的同时,也不会让其他的线程进行数据读取操作,所以说对性能使用是有非常大的缺陷的。

    DCL:JVM即时编译器的指令重排序,导致实例不会唯一。 使用volatil关键字就可以解决这个问题。

    静态内部类/枚举:延时加载instance变量/线程安全/性能优势。

    相关文章

      网友评论

          本文标题:设计模式:单例

          本文链接:https://www.haomeiwen.com/subject/ioayfctx.html