Почему ListChangeBuilder выдает исключение NullPointerException?

Я пытаюсь понять, почему получаю эту ошибку:

java.lang.NullPointerException: null
    at javafx.collections.ListChangeBuilder.findSubChange(ListChangeBuilder.java:68)
    at javafx.collections.ListChangeBuilder.insertAdd(ListChangeBuilder.java:127)
    at javafx.collections.ListChangeBuilder.nextAdd(ListChangeBuilder.java:254)
    at javafx.collections.ObservableListBase.nextAdd(ObservableListBase.java:179)
    at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:153)
    at java.util.AbstractList.add(AbstractList.java:108)
    at tech.dashman.dashman.RendererApp$1.handle(RendererApp.java:72)
    at tech.dashman.common.pubnub.NewScreenshotsToRender.handle(NewScreenshotsToRender.java:17)
    at tech.dashman.dashman.PubNubMessageHandler.lambda$message$0(PubNubMessageHandler.java:79)
    at java.lang.Thread.run(Thread.java:748)

Это случилось дважды с моим приложением, но я не знаю, как это воспроизвести. Строка в моем коде, которая вызывает ошибку, следующая:

getActivity().add(new ActivityEntry("..."));

ActivityEntry - это простой класс с двумя полями. При необходимости могу опубликовать код, но думаю, что это неактуально. activity, то, что возвращает getActivity(), представляет собой поле, определенное следующим образом:

private ObservableList<ActivityEntry> activity = FXCollections.observableArrayList();

Метод, в котором происходит фактическое исключение, выглядит так:

private int findSubChange(int idx, final List<ListChangeBuilder.SubChange<E>> list) {
    int from = 0;
    int to = list.size() - 1;

    while (from <= to) {
        int changeIdx  = (from + to) / 2;
        ListChangeBuilder.SubChange<E> change = list.get(changeIdx);

        if (idx >= change.to) {
            from = changeIdx + 1;
        } else if (idx < change.from) {
            to = changeIdx - 1;
        } else {
            return changeIdx;
        }
    }
    return ~from;
}

Строка 68, вызывающая исключение:

if (idx >= change.to) {

Единственное, о чем я могу думать, кроме ошибки в ListChangeBuilder, - это то, что это было состояние гонки, и два потока одновременно модифицировали ObservableList. Это похоже на то? ObservableList не является потокобезопасным?

Я думаю, что это может произойти, когда в список вносятся изменения, когда запускается другой слушатель изменений. Я видел это раньше, но не уверен, является ли это ошибкой в ​​JavaFX или просто (плохо документированным) ограничением дизайна.

Itai 16.03.2018 11:35
ObservableList не является потокобезопасным. Вы где-то модифицируете его из фонового потока - это не очевидно из вашего кода? Верно также и то, что это ограничение дизайна, что список не может быть изменен во время обработки изменения.
James_D 16.03.2018 11:39

Что касается последнего, см. Предупреждения в Change документация.

James_D 16.03.2018 13:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
126
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это похоже на проблему с многопоточностью, поэтому на данный момент мое решение состоит в том, чтобы определить список следующим образом:

private ObservableList<ActivityEntry> activity = FXCollections.synchronizedObservableList(FXCollections.observableArrayList());

Поскольку проблемы с многопоточностью так сложно воспроизвести и отладить, я не знаю, действительно ли это решает проблему. Я предполагаю, что если этого не произойдет, я снова замечу это в производстве.

Другие вопросы по теме