不可能(?):ConcurrentLinkedQueue.size()上的NullPointerException

时间:2013-04-29 07:16:19

标签: java nullpointerexception java.util.concurrent ibm-jre

我在 IBM JVM上获得此NPE, 1.6

  

java.lang。 NullPointerException at     java.util.concurrent.ConcurrentLinkedQueue.first( ConcurrentLinkedQueue .java: 274 )at at     java.util.concurrent.ConcurrentLinkedQueue.size(ConcurrentLinkedQueue.java:315)   。 。

相关来源显示第274行会抛出一个空的“ head ”成员。搜索用法显示此成员根据需要设置为新节点(),但从不无效。

怎么可能?我错过了什么?

...在调试模式下,我无法重现这一点。可以从多个线程访问此队列。

Snippet(Sun和IBM的消息来源相同,但更改行号的注释除外):

     Node<E> first() {
                for (;;) {
                    Node<E> h = head;
                    Node<E> t = tail;
                    Node<E> first = h.getNext(); // line #274 on IBM, #263 on Sun
...
    }
    }

2 个答案:

答案 0 :(得分:1)

这样的错误通常来自JIT编译器,它会导致一些神秘的优化错误。

你几乎无能为力;与IBM的日志错误,他们将引导您完成如何收集足够信息以调试问题的过程。

注意:在过去几年中,我们提出了两个这样的问题。因此,即使考虑到enormous testing effort that IBM spends on their VM,它们也不常见。

答案 1 :(得分:0)

可能导致这种情况的一个模糊场景:

A类包含一个静态队列,可能需要一段时间才能初始化。

class A {
  // Long process which makes a second thread access `q` while it is still being constructed.
  public Object o = aLongProcess();
  public static Queue q = new ConcurrentLinkedQueue<String>();

B类访问队列。

class B {
  ...
  void doSomething () {
    String s = A.q.first();
  }

线程T1首先访问A类 - 从而开始其初始化过程。

Object o = A.o;

线程T2在仍在初始化时访问队列。

B b = new B();
b.doSomething();

所以基本上你是在看两个线程之间的竞争条件,其中一个人认为队列已经初始化而另一个人仍在制作它。

请注意,仅仅因为对象名称以Concurrent开头并不意味着该对象的所有功能都是线程安全的。

我想另一种选择可能是你只保留对队列的弱引用,并且你试图在它被GC后访问它,但我希望你会在你的问题中提到它。