#java #linked-list #nullpointerexception #deque
#java #связанный список #исключение nullpointerexception #отмена
Вопрос:
Я использую Java 6 Collecetions API. Мне нужна коллекция, в которой должно быть только N элементов. Я имею в виду, что если я добавлю новый элемент, а в коллекции уже есть N элементов, то последний элемент должен быть удален, а новый добавлен в начало коллекции. Для этого у меня есть следующий фрагмент кода:
class A {
int N = 100;
Deque dq = new LinkedList();
void add(Object o) {
synchronized (o) {
if (dq.size() == N) {
dq.pollLast();
}
dq.add(o);
}
}
Deque getDq() {
return new LinkedList(dq);
}
}
К объекту с типом A могут обращаться многие пользователи одновременно, чтобы добавить новый элемент. На практике я получил исключение NullPointerException с ним:
Caused by: java.lang.NullPointerException
at java.util.LinkedList.remove(LinkedList.java:790)
at java.util.LinkedList.removeLast(LinkedList.java:144)
at java.util.LinkedList.pollLast(LinkedList.java:573)
at A.add(A.java:9)
В контракте Deque.pollLast() ничего не говорится об исключении NullPointerException:
Извлекает и удаляет последний элемент этого списка или возвращает null, если этот список пуст.
Также синхронизируется добавление элементов.
Кто-нибудь знает, в чем может быть причина исключения?
Спасибо за любые идеи
Комментарии:
1. Вы должны синхронизировать общий объект (т. Е. список
this
или какой-либо специальный объект блокировки), а не параметр. Хотя понятия не имею, вызывает ли это вашу проблему.2. Это тот код, который вы используете? Если да, то на каком языке вы используете?
Dequeu
не имеет открытого поляsize
, к которому вы могли бы получить доступ подобным образом.3. @user: это метод, вы получаете к нему доступ без
()
. Я знаю, что это, вероятно, опечатка, но это означает, что код, который вы нам показываете, не является кодом, в котором проблема. Пожалуйста, создайте SSCCE .4. Все обращения к
dq
правильно синхронизированы? Если нет, то это, вероятно, ваша основная проблема.
Ответ №1:
Я предполагаю, что сикронизация выполнена не для того объекта! Должно быть, dq
но не o
!
... synchronized (dg) { ...
Комментарии:
1. Я согласен с этим. Вы не предотвращаете одновременный доступ к вашему Deque, блокируя элемент, который вы пытаетесь добавить / удалить.
Ответ №2:
Я запустил добавление вашего кода, используя следующий тест
A a = new A();
for (int i = 0; i < 200; i )
{
a.add(i);
}
System.out.println(a.dq);
И все это, кажется, работает правильно. Можете ли вы предоставить более подробную информацию о состоянии приложения, когда получите NPE? Что это за объект, который вы пытаетесь добавить? Каково состояние удаления из очереди в это время?
Кроме того, вы упомянули
если я добавляю новый элемент, а в коллекции уже есть N элементов, то последний элемент должен быть удален, а новый добавлен в начало коллекции
Ваш код этого не делает. Прямо сейчас оно добавляется в конец коллекции. Чтобы добавить его в заголовок, измените
dq.add(o)
Для
dq.addFirst(o)
Комментарии:
1. Я думаю, что реальной проблемой здесь является синхронизация, а не сам алгоритм. Хотя это может быть и неправильно.
2. Очень верно. Я пытался исключить проблемы с алгоритмом и запросить дополнительную информацию о том, как используется dq и каково его состояние. Вероятно, dq используется каким-то другим несинхронизированным способом через средство доступа getDq() (как упоминали другие).
Ответ №3:
смотрите этот javadoc, в нем говорится
Removes and returns the last element from this list.
сначала он удаляет объект, поэтому, если он равен null, тогда генерируется исключение NullPointerException:
поэтому синхронизируйте метод add (..) и проверьте размер, прежде чем dq.pollLast();
Комментарии:
1. LinkedList.pollLast() не выдает исключение, если код хорошо синхронизирован: