Я пытаюсь понять, почему получаю эту ошибку:
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 не является потокобезопасным?
ObservableList не является потокобезопасным. Вы где-то модифицируете его из фонового потока - это не очевидно из вашего кода? Верно также и то, что это ограничение дизайна, что список не может быть изменен во время обработки изменения.




Это похоже на проблему с многопоточностью, поэтому на данный момент мое решение состоит в том, чтобы определить список следующим образом:
private ObservableList<ActivityEntry> activity = FXCollections.synchronizedObservableList(FXCollections.observableArrayList());
Поскольку проблемы с многопоточностью так сложно воспроизвести и отладить, я не знаю, действительно ли это решает проблему. Я предполагаю, что если этого не произойдет, я снова замечу это в производстве.
Я думаю, что это может произойти, когда в список вносятся изменения, когда запускается другой слушатель изменений. Я видел это раньше, но не уверен, является ли это ошибкой в JavaFX или просто (плохо документированным) ограничением дизайна.