9

I came across very odd Java behaviour, and I don't know if it is a bug, or am I missing something.

The code simply goes through the stateStack (LinkedList) list and destroy all the states.

public void clearStates()
{
    LogFactory.getLog(StateController.class.getName())
      .info( "Clearing states. #ofstates="+stateStack.size());
    for (State state : stateStack)  // Line 132 (see exception)
    {
        state.destroy();
    }

    // ...
} 

The following exception was trowed:

INFO  controllers.StateController : Clearing states. #ofstates=1
java.lang.NullPointerException\
    at java.util.LinkedList$ListItr.next(LinkedList.java:891)
    at *.controllers.StateController.clearStates(StateController.java:132)
    // ... //

This code usually works without a problem and has been in the production for more than a year.

Is it possible that this is Java bug?

/* Update */

destroy() call does not modify stateStack. If it would I guess Java would throw ConcurrentModificationException.

stateStack was populated with 1 state, which overrides destroy, but only does local modifications. The super implementation than prints additional log ("Destroying state..."), which was not in the log file, so I guess the exception was thrown at the beginning of iteration.

public void destroy()
{
    destroyed = true;
    LogFactory.getLog(State.class.getName()).info( "Destorying state : "+getClass().getName());
    propertyChangeSupport.firePropertyChange(PROP_DESTROYED, null, this);
}
8
  • Where is line :132? Maybe state in your list is null? Commented Aug 5, 2013 at 9:44
  • 3
    What is the implementation of state.destroy(). What does it do? Also, how is stateStack populated? Commented Aug 5, 2013 at 9:44
  • 2
    Is it possible that the list is being changed by another thread during the iteration? Commented Aug 5, 2013 at 9:46
  • 1
    It does seem to be a java bug, because it happens on iterator.next(), rather than state.destroy(). You could file a bug report Commented Aug 5, 2013 at 9:47
  • 2
    @Manuel even if the item in the list is null, the list must return null and not throw an internal exception. It looks like concurrent modification. Commented Aug 5, 2013 at 9:49

2 Answers 2

9

The piece of code below generates the same exception almost every time I run it - the idea is to modify the list while iterating from another thread. With (un-)lucky timing, the modification happens after checkForComodification but before next = next.next; in the ListItr#next method, causing a NPE.

Exception in thread "main" java.lang.NullPointerException at java.util.LinkedList$ListItr.next(LinkedList.java:891) at javaapplication4.Test1.main(Test1.java:74)

public class Test {
    public static void main(String[] args) {
        final int SIZE = 100000;
        final Random rand = new Random();
        final List<Integer> list = new LinkedList<>();
        for (int i = 0; i < SIZE; i++) {
            list.add(i);
        }

        Runnable remove = new Runnable() {

            @Override
            public void run() {
                while (true) {
                    int i = rand.nextInt(SIZE);
                    list.remove(i);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ex) {
                        break;
                    }
                    list.add(i);
                }
            }
        };
        Thread t = new Thread(remove);
        t.start();
        for (int i = 0; i < 100; i++) {
            try {
                for (Integer j: list) {
                    ///whatever
                }
            } catch (ConcurrentModificationException e) {
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
        t.interrupt();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

8

This is the internal implementation of LinkedList.ListItr.next():

public E next() {
    checkForComodification();
    if (!hasNext())
        throw new NoSuchElementException();

    lastReturned = next;
    next = next.next;   // your stacktrace says the NullPointerException happens here
    nextIndex++;
    return lastReturned.item;
}

The NullPointerException happens because the internal variable next is null; however, it seems that hasNext() is validating that there is a next element.

It seems to me that:

  • you have more than one thread modifying your list, OR
  • you are modifying your list in the implementation of destroy() while iterating over the list.

If you update your answer with your implementation of destroy() as sugested by @mthmulders, I either update, correct or delete my answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.