不寻常的Java行为 - 为什么这样做?

时间:2011-07-12 22:26:07

标签: java java-ee jms

我发现了一些有趣的行为......我无法判断这是一个错误或无能,但目前倾向于无能。

即使有等待的消息,此代码也不会进入循环:

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

此代码进入循环,注意空赋值:

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

此代码在Windows 32bit上的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();
}

最后,我说的是我自己的无能。 ;)

4 个答案:

答案 0 :(得分:3)

瑞恩说,看起来像是一场竞争。两个代码的字节码是相同的,除了额外的“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)”,以避免缓冲区欠载等。

答案 1 :(得分:1)

这对我来说听起来像是一场竞赛。没有实例化的对象声明将始终导致空值。您可能认为在第一种情况下有消息等着您,但我打赌没有消息。在条件循环之前,打印出对象的数量并验证结果行为。如果您处于多线程情况,请在必要时在消息队列上进行同步以促进此操作。我认为它的工作原理与预期一致。

答案 2 :(得分:0)

我的钱是在你没有运行你认为你的代码。你提到“在Glassfish 3.1.1b10上运行”,所以可能没有太多的单元测试方法,因此能够确定错误的位置变得更加困难。

有几种可能性可能会在一些奇怪的边缘情况下产生影响。

  • 它对类加载顺序进行了微妙的改变,你在静态初始化中做了一些狡猾的事情。我甚至不确定它是否对班级装载顺序产生影响。
  • null赋值对堆栈的引用进行了破坏,它允许对象进行垃圾回收,引用与弱/软/幻像/终结器引用一起使用的对象,或者可能仅更改内存分配时间和干扰竞争条件。

答案 3 :(得分:0)

您是否有可能提供哪些消费者对象以及receiveNoWait()可能是什么?