单例模式引发的思考【日常记录】

247 阅读2分钟
单例模式的意义

节约系统资源,尤其是频繁创建/回收对象造成的内存开销。

单例模式的应用
// Single threaded version
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) 
        helper = new Helper();
    return helper;
    }
  // other functions and members...
}

上述代码是一个懒汉式的单例模式的简单应用,在单线程环境下没有什么问题,但是在多线程环境下可能会导致创建多个实例,可以在方法上加上synchronized来解决这个问题

// Correct multithreaded version
class Foo { 
  private Helper helper = null;
  public synchronized Helper getHelper() {
    if (helper == null) 
        helper = new Helper();
    return helper;
    }
  // other functions and members...
}

每次都执行synchronized会对性能产生影响,可以采用经典的Double-Checked Locking 来进行锁优化

// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) 
      synchronized(this) {
        if (helper == null) 
          helper = new Helper();
      }    
    return helper;
    }
  // other functions and members...
}

大多数的情况下,这个实例化过程可能是没有竞争的,所以采用把synchronized后置,把check前置,并采用Double-checked的方式来消除或者说减少synchronized。

但是在多线程的情况这仍有可能带来问题,这跟JMM(Java内存模型 Java Memory Model)有关,可能导致实际结果并非预期,原因在于对象实例化过程大致分为3步:1.申请内存空间并创建对象;2.初始化对象;3.把内存地址指向引用的变量;

在多线程情况下,编译器或CPU可能会进行指令重排序,执行顺序可能是1、2、3,也可能是1、3、2,基于happens-before原则,2、3并没有依赖关系,可能A线程在执行完1、3的时候,线程B再获取Helper对象时获取到的时候一个不完整的对象,导致获取到的值并不是构造函数里设置的值而是对象实例化过程的默认值。

// Works with acquire/release semantics for volatile
// Broken under current semantics for volatile
  class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                synchronized(this) {
                    if (helper == null)
                        helper = new Helper();
                }
            }
            return helper;
        }
  }

根据JEREMY MANSONJDK的博客,1.5之后可以通过volatile解决该问题,在对象初始化时对于volatile写插入内存屏障,来禁止指令重排序,。

思考

上述观点依然有疑惑,因为没有直接的资料表明volatile一定可以解决问题,或者说这个问题一定能被复现并且volatile可以解决

参考资料

blog.csdn.net/mifffy_java…

www.cs.umd.edu/~pugh/java/…

jeremymanson.blogspot.com/2008/05/dou…