Clojure: что происходит, когда «настойчиво!» вызывается на TransientVector? - PullRequest
0 голосов
/ 06 ноября 2018

Я просматриваю исходный код компилятора clojure и столкнулся с поведением, которое не соответствует исходному коду.

Класс PersistentVector в clojure.lang (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java),, который реализован как трехраздельное дерево, имеет следующие поля:

  1. cnt (int)
  2. Хвост (Объект [])
  3. root (Node)
  4. shift (int)
  5. _meta

Node имеет два поля. edit и array.

array хранит дочерние элементы (ветви дерева), а edit - это AtomicReference<Thread>. edit содержит null для PersistentVector с и идентификатор потока создания для TransientVector с. В этом блоге очень хорошо объясняется, как на самом деле работают переходные процессы. Ключевой момент, который относится к моему запросу:

  1. Любые новые узлы, созданные с помощью переходного процесса, будут иметь поле edit, установленное в корне переходного процесса, который содержит идентификатор потока создания
  2. , когда persistent! вызывается на TransientVector, edit корневого узла устанавливается равным нулю, и PersistentVector создается из этого корня, который возвращается. Такое поведение можно увидеть здесь в исходном коде.

Обратите внимание, что в поле edit только корневого узла установлено значение null, поэтому любые новые узлы, созданные с помощью переходного процесса, с 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");

    }
}

Вывод этого кода:

Thread[main,5,main]
null
end

Вот что делает этот код:

  1. Создает PersistentVector с 32 элементами. Этот вектор будет иметь полный хвост, поэтому добавление любого элемента приведет к созданию нового узла

  2. Создано TransientVector из него.

  3. Добавляет элемент в переходный процесс. Это приведет к созданию нового узла, который будет храниться как дочерний элемент root.

  4. печатает значение поля edit этого нового узла

  5. делает переходный процесс persistent

  6. печатает поле edit того же узла.

Значение этого поля обнуляется! Я не могу понять, как это происходит. Я попытался установить точку наблюдения поля в intellij, но эта точка останова вообще не срабатывает при вызове tv1.persistent(). В чем причина такого поведения? Я пробовал это с векторами с большим количеством элементов, и значение поля edit сбрасывается для всех дочерних узлов, когда persistent вызывается на TransientVector.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...