synchronized(Singleton.class)和synchronized(obj)之间的区别

时间:2014-03-11 18:28:57

标签: java synchronization thread-safety singleton

使用以下两个版本的Singleton Classes之间有什么区别

在第一个我使用的是synchronized(Singleton.class)

在第二个我使用的是同步(Obj) //第一类     公共类Singleton {

private static Singleton obj = null;

Singleton() {
}

public static Singleton getInstance() {

    synchronized(Singleton.class){
        if (obj == null) {
        obj = new Singleton();
    }
}
    return obj;
}

}

//第二种类型

public class Singleton {

private static Singleton obj = null;

Singleton() {
}

public static Singleton getInstance() {

    synchronized(obj){
        if (obj == null) {
        obj = new Singleton();
    }
}
    return obj;
}
}

4 个答案:

答案 0 :(得分:2)

主要区别在于synchronized(obj)不起作用:第一次调用它时,objnull,因此您将看到NullPointerException }。

Demo on ideone.

另一方面,

Singleton.class永远不会null,因此您可以将其用于同步。但是,恶意代码可以执行攻击,使您的getInstance方法永远等待:他们只需锁定您的Singleton.class,并在那里等待无限。

针对此攻击的常见防御是为您的锁使用单独的私有静态对象,如下所示:

public class Singleton {

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

    Singleton() {
    }

    public static Singleton getInstance() {
        synchronized(syncRoot){
            if (obj == null) {
                obj = new Singleton();
            }
        }
        return obj;
    }
}

答案 1 :(得分:1)

第二个版本尝试在null上进行同步,这将失败。 synchronized关键字尝试获取Object引用的obj上的锁定,因为它最初为null,您将获得NulPointerException。< / p>

答案 2 :(得分:1)

它们实际上是相同的,也是一个糟糕的实现,因为obj IS NULL(在你的例子中)和代码单线程每次调用它。它应该使用双重检查锁...

第二个应该是:

public class Singleton {
   private static object syncRoot = new object();
   private static Singleton obj = null

   Singleton() {
   }

   public static Singleton getInstance() {

      if ( obj == null ){
        //ONLY SINGLE THREAD IF obj == null
        synchronized(syncRoot){
          if ( obj == null ){
             obj = new Singleton();            
          }
        }
      }
      return obj;
   }
}

答案 3 :(得分:0)

当你使用synchronized(Singleton.class)时,同步只会在第一次创建实例时应用,并且当我们有一个可能通过我们的代码运行多个线程的场景时使用它。你的if循环将负责在没有可用的情况下创建另一个实例,通过使用这种同步方式,我们减少了大量的开销,因为我们知道同步类在时间/等待方面增加了很多。