Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 同步(Singleton.class)和同步(obj)之间的差异_Java_Synchronization_Thread Safety_Singleton - Fatal编程技术网

Java 同步(Singleton.class)和同步(obj)之间的差异

Java 同步(Singleton.class)和同步(obj)之间的差异,java,synchronization,thread-safety,singleton,Java,Synchronization,Thread Safety,Singleton,使用以下两个版本的单例类之间有什么区别 首先,我使用的是synchronized(Singleton.class) 在第二次使用同步(Obj) //第一类 公营单身人士{ private static Singleton obj = null; Singleton() { } public static Singleton getInstance() { synchronized(Singleton.class){ if (obj == null) {

使用以下两个版本的单例类之间有什么区别

首先,我使用的是synchronized(Singleton.class)

在第二次使用同步(Obj) //第一类 公营单身人士{

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;
}
}

第二个版本尝试在
null
上同步,这将失败。
synchronized
关键字尝试获取由
obj
引用的
对象上的锁,并且由于它最初为
null
,您将获得
numpointerexception

第二个版本尝试在
null
上同步,这将失败。
synchronized
关键字尝试获取由
obj
引用的
对象上的锁,由于它最初为
null
,您将得到一个
numpointerException

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

另一方面,
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;
    }
}

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

另一方面,
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;
    }
}

它们实际上是相同的,而且是一个糟糕的实现,因为obj为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;
   }
}

它们实际上是相同的,而且是一个糟糕的实现,因为obj为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;
   }
}

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

当您使用synchronized(Singleton.class)时只有在第一次创建实例之前,才会应用同步,当我们有可能通过代码运行多个线程时,才会使用同步。您的if循环将考虑在已有实例可用时不创建另一个实例,通过使用这种同步方式,我们减少了很多开销,因为我们知道同步类在时间/等待方面会增加开销。

在第二个示例中,在null上同步没有意义,您在第二个版本中确实意识到,在第一次调用时,您将在
null
上进行同步?为什么不在静态初始值设定项中初始化你的单例呢?我对多线程是新手,所以不能真正理解synchronized()的作用?我的天真理解是,当我们使用synchronized()时,我们应该输入我们想要同步的对象/变量,我在下面的帖子中看到,我们想要同步“obj”,但我们将syncRoot作为参数传递,或者将泛型对象作为参数传递。syncRoot甚至没有更改状态,也没有在块中使用。或者,即使Singleton.class也不指定要同步的对象或变量,只指定类型,那么我们如何知道要同步的块/变量r。在第二个示例中,在null上同步没有意义。在第二个版本中,您确实意识到,在第一次调用时,您将在
null
上同步?为什么不在静态初始值设定项中初始化你的单例呢?我对多线程是新手,所以不能真正理解synchronized()的作用?我的天真理解是,当我们使用synchronized()时,我们应该输入我们想要同步的对象/变量,我在下面的帖子中看到,我们想要同步“obj”,但我们将syncRoot作为参数传递,或者将泛型对象作为参数传递。syncRoot甚至没有更改状态,也没有在块中使用。或者,即使Singleton.class也不指定要同步的对象或变量,只指定类型,那么我们如何知道要同步的块/变量r。我是多线程新手,因此无法真正理解synchronized(syncRoot)的作用?我天真的理解是,当我们使用synchronized()时,我们应该输入我们想要同步的对象/变量,但我看到这里我们想要同步“obj”,但我们将syncRoot作为参数传递。syncRoot甚至没有更改状态,也没有在块中使用。或者,即使Singleton.class也不指定要同步的对象或变量,只指定类型,那么我们如何知道要同步的块/变量。@Sam
synchronized
construct接受对象-任何对象,并将其用作锁。我