在看到一篇 SO 帖子后,我正在阅读 Java 中的弱引用,并意识到我真的不知道它们是什么。
以下代码摘自 Arnold、Gosling 和 Holmes 的“The Java Programming Language, Fourth Edition”中的第 457 页,第 17 章“垃圾收集和内存”
import java.lang.ref.*;
import java.io.File;
class DataHandler {
private File lastFile; // last file read
private WeakReference<byte[]>
lastData;// last data (maybe)
byte[] readFile(File file) {
byte[] data;
// check to see if we remember the data
if file.equals(lastFile) {
data = lastData.get();
if (data != null)
return data;
}
// don't remember it, read it in
data = readBytesFromFile(file);
lastFile = file;
lastData= new WeakReference<byte[]>(data);
return data;
}
}
我试图理解,只是为了练习它,如果这段代码是线程安全的,我关注的代码部分是行
data = lastData.get();
if (data != null)
return data;
我的想法如下:“数据”是线程限制的,并设置为引用“lastData”弱引用的引用。这会创建对引用对象的强引用,因此即使在空检查之后,readFile 范围之外的所有其他对引用对象的强引用都会消失(正确的术语是什么?),即使假设引用对象不可软访问,垃圾收集器也不会允许清除弱引用,从而使引用对象可终结,因为数据中仍然存在对它的本地强引用。因此,如果 data != null
行中的数据不为 null,则在下一行返回时它不能为 null。正确吗?
最佳答案
我认为示例代码不是线程安全的,但出于与使用弱引用不同的原因:
弱引用的用法很好,完全符合您指出的原因:代码创建了一个强引用,该引用保存在 data
变量中。因此,GC 无法收集字节,因此 WeakReference
也将保持完整;因此在单线程应用程序中使用此代码应该是安全的。问题来自多线程:
对 file
和 lastData
字段的访问是不同步的,因此不能保证两个线程与 一起工作readFile(..)
方法完全交互(这将是不太可能的“最佳”情况)。重要的是要注意,必须以原子方式访问这些字段,如果没有其他地方接触到它们,最简单的解决方法是将 readFile
方法声明为同步的。这会严重损害性能,因为文件读取将发生在同步块(synchronized block)内,可能导致不良争用。
关于java - 使用 WeakReference 的 Java 示例的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6383013/