1

我正在尝试找到自己的 Java Singleton 实现方式。代码如下:

public class Singleton{
   private volatile static Singleton _instance = null;
   private Singleton(){}
   public static Singleton getInstance(){
      if (_instance == null)
         Object obj = new Object();
         synchronized(obj){
            if (_instance == null)
               _instance = new Singleton();
         }
      return _instance;
}

这段代码有效吗?如果不工作,如何解决?

4

5 回答 5

3

不-您的代码不起作用,因为锁定对象是局部变量,因此每个线程都不同。

您正在尝试实现延迟初始化模式 - 在第一次使用时创建实例。

但是有一个简单的技巧可以让你编写一个不需要同步的线程安全实现!它被称为Initialization-on-demand holder idiom,它看起来像这样:

public class Singleton {
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

    private Singleton() {
    }

    // rest of class omitted
}

此代码在第一次调用 时初始化实例getInstance(),重要的是,由于类加载器的合同,不需要同步:

  • 类加载器在第一次访问类时加载类(在这种情况下Holder,唯一的访问是在 getInstance()` 方法中)
  • 当一个类被加载,并且在任何人可以使用它之前,所有的静态初始化器都保证被执行(那是当Holder's 的静态块触发时)
  • 类加载器有自己的内置同步功能,可以保证上述两点是线程安全的

这是我在需要延迟初始化时使用的一个巧妙的小技巧。您还可以获得final实例的奖励,即使它是懒惰创建的。还要注意代码是多么干净和简单。

于 2013-05-10T14:19:54.613 回答
2

非懒惰单例的棘手且非常简单的实现:

public enum TickySingleton {

    INSTANCE;

    public void doSomething() { ... }
    public Object returnSomething() { ... }
}

}

不是每个人都会喜欢这个。;)

于 2013-05-10T13:48:08.060 回答
1

如果您的同步对象是final static. 否则每个可能的并发线程都会创建自己的同步对象并锁定不同的对象。他们不会互相等待。

public class Singleton{

   private final static Object obj = new Object();
   private volatile static Singleton _instance = null;

   private Singleton(){}

   public static Singleton getInstance(){
     if (_instance == null)
        synchronized(obj){
           if (_instance == null)
              _instance = new Singleton();
         }
      }
      return _instance;
   }
于 2013-05-10T13:42:21.803 回答
1

当你写:

Object obj = new Object();
synchronized(obj){}

JVM 可以证明没有两个线程可以获取该锁(因为它是一个局部变量),因此可以完全取消同步。

关于单例的一些评论:

于 2013-05-10T14:09:37.333 回答
0

不,这不正确,您应该在 Singleton.class 上同步

class Singleton {
       private volatile static Singleton _instance;
       private Singleton(){}
       public static Singleton getInstance(){
          if (_instance == null)
             synchronized(Singleton.class){
                if (_instance == null)
                   _instance = new Singleton();
             }
          return _instance;
    }
}

这是一种已知的双重检查锁定模式,有关详细信息,请参阅http://www.ibm.com/developerworks/java/library/j-dcl/index.html

请注意,由于此类中只有一个方法,因此以下方法具有相同的目的,没有任何双重检查技巧,而且它也很懒惰

class Singleton {
       private static Singleton _instance = new Singleton();
       private Singleton(){}
       public static Singleton getInstance(){
          return _instance;
    }
}
于 2013-05-10T14:11:51.353 回答