我正在阅读一篇SO帖子后读到Java中的弱引用,并意识到我并不知道它们是什么。
以下代码来自第457页,第17章:“Java编程语言,第四版”中的“垃圾收集和内存”,作者是Arnold,Gosling和Holmes
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”WeakReference的引用。这会创建一个对引用的强引用,因此即使在null检查之后,对readFile范围之外的所有其他强引用也会消失(正确的术语是什么?),即使假设引用不可轻易到达,垃圾收集器也不会允许清除弱引用,从而使指示物最终化,因为仍然存在来自数据的本地强引用。因此,如果data != null
行中的数据不为空,则在以下行中返回时,它不能为null。正确吗?
答案 0 :(得分:2)
一旦将引用分配给本地data
变量,该对象就不符合垃圾回收的条件。它是strongly reachable,因为在线程的堆栈中有对它的引用。
答案 1 :(得分:2)
我认为示例代码不线程安全,但出于与使用弱引用不同的原因:
弱引用的用法很好,完全符合您指出的原因:代码创建了一个强引用,该引用保存在data
变量中。因此,GC无法收集字节,因此WeakReference
也将保持不变;所以在单线程应用程序中使用此代码应该是安全的。问题来自多线程:
对file
和lastData
字段的访问不已同步,因此无法保证两个使用readFile(..)
方法的线程完全相互作用(这不太可能是“最好”的情况)。重要的是要注意这些字段必须以原子方式访问,如果没有其他地方触及它们,最简单的解决方法是声明同步readFile
方法。这会严重影响性能,因为文件读取会在同步块内发生,可能导致不良争用。
答案 2 :(得分:-1)
从技术上讲,它不是线程安全的,因为lastData和lastFile不是volatile。第二个线程可以查看这些引用的旧副本。它可能对您的应用程序没有太大影响。