![singleton模式](https://i-blog.csdnimg.cn/blog_migrate/e9df0fbad25d34af5fab2be8dea89b52.png)
singleton模式
Singleton类在Java开发人员中非常常见,但是它给初级开发人员带来了许多挑战。 他们面临的主要挑战之一是如何使Singleton保持为Singleton? 也就是说,无论出于何种原因,如何防止单个实例的多个实例。 对Singleton进行双重检查锁定是一种确保在应用程序生命周期中仅创建Singleton类的一个实例的方法。 顾名思义,在双重检查锁定中,代码对一个Singleton类的现有实例进行两次检查(有和没有进行两次锁定),以确保不会创建一个以上的singleton实例。 顺便说一句,它在Java修复JDK 1.5中的内存模型问题之前就被破坏了。 在本文中,我们将看到如何为Java中的Singleton的双重检查锁定编写代码,为什么在Java 5之前破坏了双重检查锁定以及如何解决此问题。 顺便说一句,从访谈的角度来看,这也很重要,我听说有人要求对金融和服务业的公司进行手工双重检查Singleton锁定的代码,并相信我很棘手,直到您清楚地了解了什么你在做。 您还可以查看我的Singleton设计模式问题的完整列表,以进行良好的准备。
Singleton类破坏其合同的一种常见情况是多线程。 如果您要求初学者为Singleton设计模式编写代码,那么他很有可能会提出以下内容:
private static Singleton _instance;
public static Singleton getInstance() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}
并且当您指出这段代码将由多个线程并行调用时,将创建Singleton类的多个实例时,他可能会使整个getInstance()方法同步化,如第二个代码示例getInstanceTS()方法所示。 尽管它是线程安全的,可以解决多个实例的问题,但效率不是很高。 每次调用此方法时,都需要承担同步的费用,而在创建Singleton实例时,仅在第一类上才需要同步。 这将使我们进入双重检查的锁定模式,其中只有关键的代码段被锁定。 程序员称其为“双重检查锁定”,因为对_instance == null进行了两次检查,一个没有锁定,而另一个有锁定(内部同步)块。 这是Java中经过双重检查的锁定的样子:
public static Singleton getInstanceDC() {
if (_instance == null) { // Single Checked
synchronized (Singleton.class) {
if (_instance == null) { // Double checked
_instance = new Singleton();
}
}
}
return _instance;
}
从表面上看,此方法看起来很完美,因为您只需要为同步块支付一次费用,但是直到您使_instance变量volatile之前,它仍然无效。
如果没有volatile修饰符,则Java中的另一个线程可能会看到_instance变量的一半初始化状态,但是由于volatile变量保证了before-before关系的发生,所有写入都会在_instance变量的任何读取之前发生在volatile _instance上。
在Java 5之前不是这种情况,这就是为什么以前双重检查锁定已被破坏的原因。
现在,有了事前保证,您可以放心地认为这将起作用。
顺便说一下,这不是创建线程安全的Singleton的最佳方法,可以将Enum用作Singleton ,它在实例创建过程中提供内置的线程安全性。
另一种方法是使用静态持有人模式。
/*
* A journey to write double checked locking of Singleton class in Java.
*/
class Singleton {
private volatile static Singleton _instance;
private Singleton() {
// preventing Singleton object instantiation from outside
}
/*
* 1st version: creates multiple instance if two thread access
* this method simultaneously
*/
public static Singleton getInstance() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}
/*
* 2nd version : this definitely thread-safe and only
* creates one instance of Singleton on concurrent environment
* but unnecessarily expensive due to cost of synchronization
* at every call.
*/
public static synchronized Singleton getInstanceTS() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}
/*
* 3rd version : An implementation of double checked locking of Singleton.
* Intention is to minimize cost of synchronization and improve performance,
* by only locking critical section of code, the code which creates
instance of Singleton class.
* By the way this is still broken, if we don't make _instance volatile,
as another thread can
* see a half initialized instance of Singleton.
*/
public static Singleton getInstanceDC() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}
}
这就是有关Java中Singleton类的双重检查锁定的全部内容。 这是在Java中创建线程安全的Singleton的有争议的方法之一,就将Enum用作Singleton类而言,还有其他更简单的选择。 我不建议您像那样实现Singleton,因为有许多更好的方法可以在Java中实现Singleton模式。 虽然,这个问题具有历史意义,并且还教导了并发如何引入细微的错误。 正如我之前所说,从访谈的角度来看,这非常重要。 在进行任何Java面试之前,练习手工编写Singleton类的双重检查锁定。 这将使您深入了解Java程序员所犯的编码错误。 与此相关的是,在现代的测试驱动开发中,由于Singleton难以模拟其行为,因此Singleton被视为反模式,因此,如果您是TDD实践者,最好避免使用Singleton模式。
翻译自: https://www.javacodegeeks.com/2014/05/double-checked-locking-on-singleton-class-in-java.html
singleton模式