9

Java の非常に奇妙な動作に遭遇しました。これがバグなのか、それとも何か不足しているのかわかりません。

このコードは、stateStack (LinkedList) リストを調べて、すべての状態を破棄するだけです。

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

    // ...
} 

次の例外が発生しました。

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)
    // ... //

このコードは通常問題なく動作し、1 年以上にわたって運用されています。

これはJavaのバグである可能性はありますか?

/ * 更新 * /

destroy() 呼び出しは、stateStack を変更しません。もしそうなら、JavaはConcurrentModificationExceptionをスローすると思います。

stateStack には、destroy をオーバーライドする 1 つの状態が取り込まれましたが、ローカルの変更のみが行われます。ログファイルになかった追加のログ(「Destroying state ...」)を出力するよりもスーパー実装なので、反復の最初に例外がスローされたと思います。

public void destroy()
{
    destroyed = true;
    LogFactory.getLog(State.class.getName()).info( "Destorying state : "+getClass().getName());
    propertyChangeSupport.firePropertyChange(PROP_DESTROYED, null, this);
}
4

2 に答える 2

8

これは の内部実装です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;
}

これNullPointerExceptionは、内部変数nextnull;であるために発生します。ただし、hasNext()次の要素があることを検証しているようです。

それは私には思われる:

  • リストを変更するスレッドが複数ある、または
  • destroy()リストを繰り返し処理しながら、の実装でリストを変更しています。

destroy()@mthmulders によって提案された実装で回答を更新すると、回答を更新、修正、または削除します。

于 2013-08-05T09:56:38.330 に答える
8

以下のコードは、実行するたびにほぼ同じ例外を生成します。これは、別のスレッドから反復しながらリストを変更するという考え方です。(不) 運の悪いタイミングでは、変更がメソッドのcheckForComodification前後next = next.next;ListItr#next発生し、NPE が発生します。

java.util.LinkedList$ListItr.next(LinkedList.java:891) でのスレッド「メイン」の java.lang.NullPointerException

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();
    }
}
于 2013-08-05T09:56:59.130 に答える