什么时候引用需要是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
方法的线程:
- Thread-1执行第1行,并将
result
视为null
。 - Thread-1获取第2行的类级别锁定
- Thread-1在第3行查找
result
为null
- Thread-1开始实例化一个新的
Helper
- 虽然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 }