簡體   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