【问题标题】:Impossible (?): NullPointerException on ConcurrentLinkedQueue.size()不可能 (?):ConcurrentLinkedQueue.size() 上的 NullPointerException
【发布时间】:2013-04-22 19:02:20
【问题描述】:

我在 IBM JVM、1.6 上获得此 NPE:

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

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

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

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

片段(Sun 和 IBM 来源相同,只是 cmets 会稍微改变行号):

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

【问题讨论】:

  • 如果您使用的是 IBM 的 Java,那么您肯定使用的是他们的产品之一(例如 WAS)。因此,您没有支持合同吗?如果是这样,只需向 IBM 提出 PMR,他们有成群的开发人员只是坐在那里等待这样的事情:-)
  • 谢谢,确实在用WAS,不过我觉得没关系,想用和丰富社区,不只是IBM……Sun和IBM这门课的源码是相同的(除了移动行号的 cmets)。
  • 好吧,一旦 IBM 回复您并回复您,您就可以丰富社区。我认为 IBM 从维护合同中赚取的巨额资金,他们应该修复自己的自己的软件。

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


【解决方案1】:

此类错误通常来自 JIT 编译器,导致一些神秘的优化错误。

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

注意:在过去几年中,我们提交了两个此类问题。所以即使考虑到enormous testing effort that IBM spends on their VM,它们也并不少见。

【讨论】:

  • 谢谢,亚伦。 JIT,是的,没有想到,过去它曾经给我们带来很多奇怪的问题。我可以尝试禁用它,看看它是否有帮助(可以为单个方法禁用它吗?类?)。看看 IBM 是否对此有什么聪明的说法,但我不能强迫我的客户禁用 JIT 或安装 IBM 的 JVM 补丁,即使他们生产了一个......我的应用程序在我不拥有的 WAS 上运行:-(
  • 你不能强迫你的客户,但你也不能解决问题。他们可能会强迫您重写代码以避免ConcurrentLinkedQueue,但这并不能解决任何问题——他们可能会在不同的地方遇到同样的问题。因此,您务必要与他们沟通,说明此问题超出了您以任何合理方式解决的范围。
【解决方案2】:

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

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>();

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

【讨论】:

  • 谢谢,OldCurmudgeon。不是这样 - 在队列初始化和使用后的一段时间内发生异常。队列没有弱引用,而且,我们知道队列本身是活动的,只有它的“头”是空的......
  • @adaf - 如果 IBM 确实与 this 相同,则 head 在构造时被初始化并且永远不会改变。因此,您所描述的内容是不可能的,除非 1. 它是一种竞争条件或 2. 它是不同的。
  • 代码确实是一样的,你是对的,虽然“头”不是最终的,它只是设置在构造和反序列化(或通过不友好的反射)。仍然会发生这个错误,我想 JIT 确实是答案。
猜你喜欢
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 2016-02-13
  • 2021-03-12
  • 1970-01-01
相关资源
最近更新 更多