2014-09-01 38 views
0

我想确保我的Singleton实例可以安全地使用并且同步最少,但是我对第一个if子句在synchronized块之外有疑问。如果INSTANCE没有完全构建,它有可能具有非空值吗?如果是的话,我该如何解决这个问题。以下Singleton可以在多线程环境中不安全

我认为包括整个get()块会降低效率,因为会有这么多的配置变量,必须通过这个get()方法从程序的不同部分每秒钟读取数千次。

public class ConfsDBLoader { 

    private static ConfsDBLoader INSTANCE = null; 
    private static final Object lock = new Object(); 

    private ConfsDBLoader() { //Codes loading the db objects 
    } 

    public static ConfsDBLoader get(){ 
     if(INSTANCE != null){ 
      return INSTANCE; 
     } else { 
      synchronized(lock){ 
       if(INSTANCE == null){ 
        INSTANCE = new ConfsDBLoader(); 
       } 
       return INSTANCE; 
      } 
     } 
    } 

} 

注:我不能使用静态初始化,因为我的SessionFactory的静态初始化,我想有一个互相需要复杂的静态结构。事实上,我已经拥有它了,我不想让它变得越来越复杂,并且调查这些静态属性尝试彼此使用的位置。

+1

我假设你知道有哪些已经出现了更简单的方法大约十年。你能让我们知道你在考虑什么,为什么他们不合适? – 2014-09-01 16:46:09

+1

您正在使用一种非常古老且非常出名的反模式。它不是线程安全的。第二个调用者可以在第一个调用者仍在初始化INSTANCE时找到非空的INSTANCE。 – gnasher729 2014-09-01 16:47:30

+0

你是说我应该嵌套两个同步?但它效率不高! – Johnny 2014-09-01 16:48:30

回答

2

否。没有足够的同步来确保您在INSTANCE上看到正确的值。如果您的ConfsDBLoader因为在另一个线程调用getInstance()时可能无法正确构造而出现,您可能会看到一个非null,但是已损坏的实例。

你有3种选择:

  • 渴望初始化,并做最后
  • 同步整个方法
  • 使瞬间volatile
+0

我拒绝前两个,但它只能用volatile关键字?!这就是我所怀疑的。它会有足够的效率吗? – Johnny 2014-09-01 16:50:44

+0

@Johnny通过“足够高效”来定义你的意思吗? – 2014-09-01 16:52:15

+0

@Johnny同步整个方法有一些开销,但你多久打一次调用get方法?在某个时候,你会在你的课堂上缓存一个本地实例,对吧?如果我不得不在两者之间进行选择,并且热切加载对象不是问题,那么我只需要选择选项1. – coffeeaddict 2014-09-01 18:03:34

相关问题