簡體   English   中英

不尋常的 Java 行為 - 為什么會這樣?

[英]Unusual Java behavior - why does this work?

我發現了一些有趣的行為......我無法確定這是錯誤還是無能,但目前傾向於無能。

這段代碼不會進入循環,即使有消息在等待:

Message msg;
while ((msg = consumer.receiveNoWait()) != null) {
    System.out.println(msg);
}

此代碼確實進入了循環,請注意 null 分配:

Message msg = null;
while ((msg = consumer.receiveNoWait()) != null) {
    System.out.println(msg);
}

此代碼在 Windows 32 位上的 Glassfish 3.1.1b10 HotSpot 1.6_26 上運行。 我想不出為什么第一個塊不起作用的解釋!

編輯/更新 2011 年 7 月 13 日:

首先,我開始停止 Glassfish 域並在每次請求的部署之間刪除它,這仍然會發生:)

其次,我無法在 Destination 或 Consumer 上同步,因為這是 Java EE 代碼。 但是,我可以保證有可用的消息。 其中大約有 500 個可用且沒有消費者。 事實上,創建一個 QueueBrowser 告訴我有可用的消息!

第三,這個程序打印“WORKS!” 每次!!! 啊!!!

public static void main(String[] args) {
    Object obj;

    if ((obj = getNotNull()) != null) {
        System.out.println("worked!");
    } else {
        System.out.println("failed!");
    }
}

static Object getNotNull() {
    return new Object();
}

最后,我說的是我自己的無能。 ;)

正如瑞安所說,這似乎是一種競賽條件。 兩個代碼的字節碼是相同的,除了一個額外的“astore”:

public static void code1()   throws javax.jms.JMSException;
  Code:
   0:   getstatic   #2; //Field consumer:Ljavax/jms/MessageConsumer;
   3:   invokeinterface #3,  1; //InterfaceMethod javax/jms/MessageConsumer.receiveNoWait:()Ljavax/jms/Message;
   8:   dup
   9:   astore_0
   10:  ifnull  23
   13:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   16:  aload_0
   17:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   20:  goto    0
   23:  return

public static void code2()   throws javax.jms.JMSException;
  Code:
   0:   aconst_null
   1:   astore_0
   2:   getstatic   #2; //Field consumer:Ljavax/jms/MessageConsumer;
   5:   invokeinterface #3,  1; //InterfaceMethod javax/jms/MessageConsumer.receiveNoWait:()Ljavax/jms/Message;
   10:  dup
   11:  astore_0
   12:  ifnull  25
   15:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   18:  aload_0
   19:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   22:  goto    2
   25:  return

}

如果你想測試這個理論,試試這個代碼:

Message msg;
String dummy = null;
while ((msg = consumer.receiveNoWait()) != null) {
    System.out.println(msg);
}

這是一個 noop,但字節碼與第二個代碼幾乎相同(將“astore_0”更改為“astore_1”)。

順便說一句,我用“receiveNoWait”得到了可怕的結果。 我更喜歡“receive(smallTimeout)”,以避免緩沖區不足等。

這對我來說聽起來像是一種競爭條件。 沒有實例化的對象聲明將始終導致 null 值。 您可能認為在第一種情況下有消息在等着您,但我敢打賭沒有。 在條件循環之前,打印出對象的數量並驗證結果行為。 如果您處於多線程情況,請在必要時在消息隊列上同步以促進此操作。 我敢打賭它會完全按預期工作。

我的錢是你沒有運行你認為的代碼。 您提到“在 Glassfish 3.1.1b10 上運行”,因此單元測試的方式可能並不多,因此查明錯誤所在位置的能力變得更加困難。

在一些奇怪的邊緣情況下,有幾種可能性可能會有所不同。

  • 它對 class 加載順序進行了細微的更改,並且您在 static 初始化中做了一些狡猾的事情。 我什至不確定它是否對 class 加載順序有影響。
  • The null assignment clobbers a reference on the stack, which allows an object to be be garbage collected that references an object that is used with a weak/soft/phantom/finaliser reference, or perhaps just changes memory allocation timings and disturbs a race condition.

您是否可以提供消費者 oject 可能是什么以及 receiveNoWait() 可能是什么?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM