Java设计模式之Singleton——四种不同的单例模式(Singleton)

单例模式(Singleton [?sglt?n])

如果要保证系统里最多只能存在一个实例时,我们就需要单例模式。例如缓存池、数据库连接池等。

实例一:最简单的单例模式

因为JVM在加载类时,对于static属性的初始化只能由一个线程执行且仅执行一次,并且return操作是原子性的,所以,该方式是线程安全的。

实例二:延迟创建的单例模式(出于性能等方面的考虑)

延迟创建:在调用方法的时候创建实例,而不是在类加载的时候创建,这样可以提高性能。
虽然延迟创建的方式可以提高性能,但是,它不是线程安全的。因为可能存在多个线程同时访问代码块:

这样就会创建多个DelayBuildSingleton实例。为了解决这个问题,雅思托福我们可以声明getInstance()方法是synchronized的。但是在高并发访问的情况下,给这个方法加上Synchronized关键字会使得性能大不如前。为了解决这些问题,我们可以使用Double-Check Locking方式。

实例三:Double-Check Locking

不了解volatile以及synchronized相关知识的,推荐先阅读《Thining in Java》并发章节。
volatile关键字保证了instance的可视性,synchronized代码块保证了实例化操作的原子性。他们一起协作,使得该方法是线程安全的。(关于volatile关键字,推荐一篇详解博客:http://www.importnew.com/18126.html)
该方式同时保证了线程安全和延迟创建。还有一种方式同样可以达到此目的:

实例四:使用静态私有内部类

只有在第一次调用getInstance()方法时,JVM才会加载LazyHolder类,并初始化静态变量instance,这实现了延迟加载。同实例1一样,该方式是线程安全的。

上面介绍了四种单例模式的实现方式。具体使用时,我们应该根据具体上下文环境来选择。比如,在多线程环境下,应该选用线程安全的方式,如实例一、三、四。当性能需要优化时,则考虑实例二、实例四。通常情况下,实例四是推荐的方式,因为它同时满足了性能和线程安全,同时代码也并不复杂。

猜你喜欢

转载自blog.csdn.net/jiangziya1491/article/details/82980437