繁体   English   中英

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

[英]Impossible (?): NullPointerException on ConcurrentLinkedQueue.size()

我在IBM JVM上获得了这个NPE, 1.6

java.lang中。 java.util.concurrent.ConcurrentLinkedQueue.size上的java.util.concurrent.ConcurrentLinkedQueue.first( ConcurrentLinkedQueue .java: 274 )中的NullPointerException (ConcurrentLinkedQueue.java:315)。

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

怎么会这样? 我错过了什么?

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

片段(除了更改行号的注释之外,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
...
    }
    }

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

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

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

一个不起眼的场景可能导致这种情况:

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之后访问它,但我希望你会在你的问题中提到它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM