繁体   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