我正在浏览clojure编译器的源代码,并且遇到了似乎与源代码不匹配的行为。
PersistentVector
(https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java)中的clojure.lang
类(按位分区的特里实现)具有以下字段:
Node
有两个字段。 edit
和array
。
array
存储子项(trie的分支),而edit
是AtomicReference<Thread>
。 edit
包含null
的{{1}}和PersistentVector
的创建线程的ID。 This博客文章很好地解释了瞬态实际上是如何工作的。与我的查询有关的关键点是:
TransientVector
字段设置为暂态根的字段,其中包含创建线程的ID edit
上调用persistent!
时,根节点的TransientVector
设置为null,并从该根节点创建一个edit
,并将其返回。可以在源代码中here看到这种行为。请注意,仅根节点的PersistentVector
字段设置为null,因此,由暂态创建的edit
设置为线程ID的任何新节点都不会受到影响。因此,我编写了以下代码来测试这种情况:
edit
此代码的输出是:
package clojure.lang;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<>();
for (int i=0; i<32; i++) {
arr.add(i);
}
PersistentVector pv1 = PersistentVector.create((Iterable)arr);
PersistentVector.TransientVector tv1 = pv1.asTransient();
tv1.conj(-1);
PersistentVector.Node n = (PersistentVector.Node) tv1.root.array[0];
System.out.println(n.edit);
PersistentVector pv2 = tv1.persistent();
n = (PersistentVector.Node) pv2.root.array[0];
System.out.println(n.edit);
System.out.println("end");
}
}
这就是这段代码的作用:
创建一个包含32个元素的Thread[main,5,main]
null
end
。该向量将具有完整的尾部,因此向其添加任何元素将导致创建新节点
从中创建了一个PersistentVector
。
为瞬变添加一个元素。这将导致创建一个新节点,并将其存储为TransientVector
的子节点。
打印此新节点的root
字段的值
使瞬态edit
打印同一节点的persistent
字段。
该字段的值将重置为null!我不知道怎么回事。我曾尝试在intellij中设置字段监视点,但是调用edit
时根本不会触发该断点。这种行为背后的原因是什么?我已经尝试过使用具有更多元素的向量,并且在tv1.persistent()
上调用edit
时,所有子节点的persistent
字段的值都会重置。