3

我在IBM JVM 1.6上得到了这个 NPE :

java.lang. 在 java.util.concurrent.ConcurrentLinkedQueue.size(ConcurrentLinkedQueue.java:315) 的java.util.concurrent.ConcurrentLinkedQueue.first( ConcurrentLinkedQueue .java: 274 ) 处出现NullPointerException 。. .

相关资料显示第 274 行抛出了一个空的“ head ”成员。搜索用法显示此成员根据需要设置为新的 node(),但永远不会被取消。

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

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

片段(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
...
    }
    }
4

2 回答 2

1

像这样的错误通常来自 JIT 编译器,它得到了一些神秘的优化错误。

你无能为力;与 IBM 记录错误,然后他们将指导您完成如何收集足够的信息以供他们调试问题的过程。

注意:在过去几年中,我们提交了两个此类问题。因此,即使考虑到IBM 在其 VM 上花费的大量测试工作,它们也并不少见。

于 2013-04-29T08:07:14.153 回答
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 之后访问它,但我希望你会在你的问题中提到这一点。

于 2013-04-29T08:27:24.517 回答