什么时候引用需要是primefaces的?

在Java中以primefaces方式分配引用意味着什么?

  • 我明白它对long和double意味着什么,即:一个线程可以看到部分构造的数字,
  • 但是对于一个我不理解的对象,因为赋值并不意味着只是指向内存中的地址

那么,如果引用赋值在Java中不是primefaces的,那会是什么错误?

这意味着你永远不会得到损坏的引用。 假设您有以下课程:

class MyClass { Object obj = null; } 

在内存中obj是一个空指针,通常它是一个整数,如0x00000000 。 然后假设在一个线程中你有一个任务:

 this.obj = new Object(); 

假设在内存中分配了new Object()并且指针类似于0x12345678 。 参考primefaces性确保当您从另一个线程检查obj ,您将具有空指针( 0x00000000 )或指向新对象的指针( 0x12345678 )。 但在任何情况下,您都无法获得部分分配的引用(如0x12340000 )。

这可能看起来很明显,但这种问题可能出现在像C这样的低级语言中,具体取决于CPU架构和内存对齐。 例如,如果指针未对齐并穿过缓存行,则可能无法同步更新。 为了避免这种情况,Java虚拟机始终对齐指针,因此它们永远不会跨越缓存行。

那么Java引用是非primefaces的,当解除引用从另一个线程写入的引用时,你有可能得到的不是在赋值之前或之后引用的对象,而是随机内存位置(可能导致分段错误,损坏)堆或任何其他灾难)。

让我们考虑经典的双重检查锁定示例来理解为什么引用需要是primefaces的:

 class Foo { private Helper result; public static Helper getHelper() { if (result == null) {//1 synchronized(Foo.class) {//2 if (result == null) {//3 result = new Helper();//4 } } } return result//5; } // other functions and members... } 

让我们考虑两个将调用getHelper方法的线程:

  1. Thread-1执行第1行,并将result视为null
  2. Thread-1获取第2行的类级别锁定
  3. Thread-1在第3行查找resultnull
  4. Thread-1开始实例化一个新的Helper
  5. 虽然Thread-1仍在第4行实例化一个新Helper ,但Thread-2执行第一行。

步骤4和5是可能出现不一致的地方。 在步骤4,有可能没有完全实例化对象,但result变量已经在其中标记了部分创建的Helper对象的地址。 如果在Helper对象完全初始化之前,Step-5甚至执行纳秒,则Thread-2将看到result引用不为null并且可能返回对部分创建的对象的引用。

解决问题的方法是将result标记为volatile或使用AtomicReference 。 话虽如此,上述场景在现实世界中极不可能发生,并且有更好的方法来实现Singleton不是使用双重检查锁定。

以下是使用AtomicReference实现双重检查锁定的示例:

 private static AtomicReference instance = new AtomicReference(); public static AtomicReferenceSingleton getDefault() { AtomicReferenceSingleton ars = instance.get(); if (ars == null) { instance.compareAndSet(null,new AtomicReferenceSingleton()); ars = instance.get(); } return ars; } 

如果您有兴趣知道为什么步骤5会导致内存不一致,请查看此答案(如评论中的pwes所示 )

我假设你问的是AtomicReference

这个想法是,如果两个或多个线程读取或更新引用类型变量的值,您可能会得到意外的结果。 例如,假设每个线程检查某个引用类型变量是否为null,如果它为null,则创建该类型的实例并更新该引用变量。

如果两个线程同时看到变量为null,则可能导致创建两个实例。 如果您的代码依赖于使用该变量引用的同一实例的所有线程,那么您将遇到麻烦。

现在,如果使用AtomicReference ,则可以使用compareAndSet(V expect, V update)方法解决此问题。 因此,只有当某个其他线程没有将其击败时,线程才会更新变量。

例如 :

 static AtomicReference ref = new AtomicReference<> (); ... // code of some thread MyClass obj = ref.get(); if (obj == null) { obj = new MyClass(); if (!ref.compareAndSet (null, obj)) // try to set the atomic reference to a new value // only if it's still null obj = ref.get(); // if some other thread managed to set it before the current thread, // get the instance created by that other thread }