在一个多线程的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%安全?
第一种方法肯定是不安全的。对get
的每个调用都是独立的。没有什么可以阻止 GC 在第一次get
之后和第二次之前清除弱可访问的对象。
javadoc 状态
假设垃圾回收器在对象微弱可到达的时间。到时候它会 原子清除对该对象的所有弱引用和所有弱引用 对任何其他弱可访问对象的引用,从中可以 对象可通过一系列强引用和软引用进行访问。
这可以是在任何时间点。调用 get()
,它(可能)推送对堆栈上对象的引用,暂时使对象具有很强的可访问性(它在线程的堆栈上),但这种可访问性在与null
的比较结束时消失了。在此之后,GC 可以确定对象是弱可访问的,并清除其引用。然后你会得到一个NullPointerException
.
使用第二种方法。但请注意,通过将其分配给变量,可以使引用的对象具有很强的可访问性。