Java多线程:创建单例对象

时间:2014-06-13 10:51:53

标签: java multithreading

从线程角度看静态和易失性引用有什么区别? 例如,我想要一个单例对象,我的代码是这样的:

class Singleton {
    Helper helper;   /*Shall I make this variable static or volatile*/

    Helper getHelper() {
          if(helper==null) {
              synchronized(this) {
                  if(helper==null) {  
                      helper=new Helper();
                  }
              }
          }
          return  helper;
     } 
}

假设有两个线程访问getHelper()方法。为避免多次创建Helper对象和脏读,我应该将引用设为static还是volatile?

任何人都可以解释一下线程缓存到图片中吗?

3 个答案:

答案 0 :(得分:4)

对于这种延迟初始化,它需要是易失性的。

要使它成为单身人士,它必须是静态的。

所以你需要两个:)

有一个更简洁的模式可用于懒惰初始化静态单例,虽然它使用类加载器为你完成所有工作:

class Singleton {
     private static class SingletonHolder {
          private static final Singleton instance;
     }

     Singleton getInstance() {
        return SingletonHolder.instance;
     }
}

内部类仅在您第一次使用时加载,这意味着从外部类的角度来看它是延迟加载的。类加载器会为您处理所有同步。

答案 1 :(得分:1)

如果应用程序是多任务处理,则从Head First Design Patterns开始,您应该使用private volatile static修改器。 易失性修饰符确保在多线程环境中正确处理该字段。没有它,仍然可能存在一种情况,即创建多个对象。 所以你的代码应该像

class Singleton {
    private volatile static Helper helper;

    public static Helper getInstance(){
      if(helper==null) {
        synchronized(this) {
           if(helper==null){  
                 helper=new Helper();
           }
        }
    }
   return  helper;
   } 
}

答案 2 :(得分:0)

如果Helper是一个沉重的类,你只想拥有一个(在Singleton中)你应该让它静止。同步块内的实例化将阻止它导致问题。但是,Helper类中的任何非线程安全方法也应该适当地同步。