24

6种单例写法,你会写几种?

 5 years ago
source link: https://www.tuicool.com/articles/AJBzMbu
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

第一种:饿 汉方式

Q3YZRf3.jpg!web

优点:代码简单易读,由JVM类加载机制保证了线程安全,无需业务方关心。

缺点:无法做到延迟创建对象,在加载class的时候就会创建对象。

第二种:懒汉方式(线程不安全)

qeeMnqV.jpg!web

优点:代码简单易读。

缺点:在多线程情况下非现场安全,可能出现创建多个实例。

第三种:懒汉方式(线程安全)

jyMBJjY.jpg!web

优点:代码简单易读,线程安全。

缺点:每次调用时,都需要线程同步,性能较差。

第四种:内部类方式

ZzIJJn2.jpg!web

优点:由JVM保证线程安全,不需要业务方关心。

缺点:第一次访问可能较慢,他需要加载内部类这样可能占用更多的code区域的内存。

第五种:枚举

yEvYnyr.png!web

枚举在单例上的使用较其他有点不太一样,使用示例如下:

Singleton.INSTANCE.doSomeThing();

优点:由JVM保证了线程安全,代码简洁。

缺点:代码不易理解。

Joshua Bloch大神较为推崇这种写法,他在《Effective Java》中明确表达过下面观点:

使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。

第六种:双重校验锁

yI3Ufyb.jpg!web

优点:线程安全

缺点:每次访问对象都需要判null,并且volatile导致每次都会访问主内存,性能相比较而言较差。 该单例模式较容易出错,特别是volatile关键字要加,具体原因可以参考: Java面试官最喜欢问的关键字-volatile

总结

线程安全

性能

可读性

延迟加载

推荐使用不

恶汉

推荐

懒汉(非线程安全)

不推荐

懒汉(线程安全)

不推荐

内部类

一般

一般

枚举

一般

推荐

双重校验锁

一般

一般

一般

具体选择哪种方式肯定是具体场景具体分析;但是一般情况下,我是比较推荐恶汉和枚举方式。

大家如果阅读过JDK源码可能就会注意到,JDK主要采用的恶汉和懒汉模式,基本上不会采用枚举、双重校验锁;我猜测可能的原因双重双重校验锁再JDK1.5版本之前有问题并且枚举是在JDK1.5版本才引用的,导致历史上很多JDK在实现单例模式没有那么多选择。

其他很多开源项目在选择单例上就较为丰富,基本上每种单例都可能遇到,比如在Hystrix就遇到了恶汉模式(HystrixTimer)和内部类(HystrixPlugins)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK