在使用java之前测试弱引用

2022-09-01 23:46:11

在一个多线程的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

第一种方法肯定是不安全的。每个调用都是独立的。没有什么可以阻止 GC 在第一个对象之后和第二个对象之前清除弱可到达的对象。getget

javadoc 状态

假设垃圾回收器在某个时间点确定某个对象的可访问性很弱。届时,它将原子清除对该对象的所有弱引用,以及对任何其他弱可访问对象的所有弱引用,该对象可通过强引用和软引用链访问。

这可以是在任何时间点。调用 ,(可能)暂时将对对象的引用推送到堆栈上,使对象强烈可访问(它位于线程的堆栈上),但是当与完成比较时,这种可访问性就会消失。在此之后,GC可以确定对象是否可弱,并清除其引用。然后,您将获得.get()nullNullPointerException

使用第二种方法。但请注意,通过将其分配给变量,可以使引用的对象强力访问。


答案 2

推荐