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