简体   繁体   中英

Impossible (?): NullPointerException on ConcurrentLinkedQueue.size()

I'm getting this NPE on IBM JVM, 1.6 :

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

Relevant source shows that line #274 throws on a null " head " member. Search for usages shows this member is set to a new node() as needed, but is never nullified.

How could that be? What am I missing?

... I cannot reproduce this when in debug mode. This queue is accessed from multiple threads.

Snippet (Sun&IBM sources identical except for comments that change line numbers a bit):

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

Errors like that often come from the JIT compiler which gets some arcane optimization wrong.

There is little you can do; log error with IBM, they will then guide you through the process how to collect enough information for them to debug the issue.

Note: In the last years, we filed two such issues. So they aren't that uncommon even taking into account the enormous testing effort that IBM spends on their VM .

One obscure scenario that could cause this:

An class A holds a static queue that could take a while to be initialised.

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 class B accesses the queue.

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

Thread T1 is first to access class A - thus beginning its initialisation process.

Object o = A.o;

Thread T2 accesses the queue while it is still being initialised.

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

So basically you are looking at a race condition between two threads where one thinks the Queue is initialised while the other is still making it.

Note that just because the object name starts with Concurrent does not mean all functionality of the object is thread safe.

I suppose another alternative could be that you only hold weak references to the queue and you are attempting to access it after it has been GC'd but I would expect you would mention that in your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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