在使用Java中的弱引用之前,请先测试它

23
在一个多线程的Android项目中,我看到类似这样的代码:
final WeakReference<MyClass> myClassObjectWeakRef =
                new WeakReference<MyClass>(aMyClassObject);

...然后在别的地方:

if (myClassObjectWeakRef.get() != null) {
  myClassObjectWeakRef.get().someMethod();
}

我相信在检查引用和使用引用之间存在竞态条件的可能性,如果另一个线程中释放了对象的最后一个强引用,但我找不到任何文件或人能够比“你可能是正确的”更好地确认这一点。

我认为测试和使用弱引用的唯一正确方法是像这样完成:

MyClass myObject = myClassObjectWeakRef.get();
// we now have a strong reference, or null: standard checks apply.
if (myObject != null) {
  myObject.someMethod();
}

我非常自信第二种方法是100%安全的,但我想知道是否有一些Java /编译器的特殊技巧或魔术,我不知道是否能使第一种方法变得安全。

那么,第一种方法是100%安全的吗?


1
你可能是对的,;-) - petey
3
不能有任何内置的Java/编译器糖/魔法来确保方法#1始终有效。你对这种情况的理解和我的理解一样。 - NoseKnowsAll
1个回答

15
第一个方法绝对不安全。每次调用`get`都是独立的。没有任何东西阻止GC在第一次`get`和第二次之间清除弱可达对象。 javadoc指出:
假设垃圾收集器在某个时间点确定一个对象是弱可达的。此时,它将原子性地清除所有对该对象的弱引用以及从该对象通过强引用和软引用链可达的任何其他弱可达对象的弱引用。
这可能发生在任何时间点。调用`get()`可能会将对象的引用暂时推到堆栈上,使其成为强可达(位于线程的堆栈上),但是在与`null`的比较完成后,可达性就消失了。在那之后,GC可以确定对象是弱可达的并清除其引用。然后你会得到一个`NullPointerException`。
使用第二种方法。但要注意,通过将其分配给变量,您正在使所引用的对象强可达。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接