开发者

Unusual Java behavior - why does this work?

开发者 https://www.devze.com 2023-03-20 01:31 出处:网络
I\'ve found some interesting behavior... I can\'t decide if it\'s a bug or incompetence, but currently leaning towards incompetence.

I've found some interesting behavior... I can't decide if it's a bug or incompetence, but currently leaning towards incompetence.

This code will not enter the loop, even if there are messages waiting:

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

This code DOES enter the loop, notice the null assignment:

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

This code is running on Glassfish 3.1.1b10 HotSpot 1.6_26 on Windows 32bit. I can't think of an explanation why the first block doesn't work!

EDIT/UPDATE July 13, 2011:

First, I began stopping the Glassfish domain and deleting it between deploys per request, and this still occurs :)

Second, I cannot sync on Destination or Consumer, as this is Java EE code. But, I can assure there are messages available. There's about 500 of them available an no consumers. In fact, creating a QueueBrowser tells me there's messages available!

Third, this program prints "WORKS!" every time!!! ARGH!!!

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

    if ((obj = getNotNull()) != null) {
        Syste开发者_开发问答m.out.println("worked!");
    } else {
        System.out.println("failed!");
    }
}

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

Lastly, I was speaking about my own incompetence. ;)


As Ryan said, seems like a race condition. The bytecodes for both codes are the same, with the exception of an extra "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

}

If you want to test this theory, try this code:

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

It's a noop, but the bytecode is almost the same as the second code (changes "astore_0" to "astore_1").

BTW, I had horrible results with "receiveNoWait". I prefer "receive(smallTimeout)", to avoid buffer underruns or such.


This sounds like a race condition to me. Declaration of objects without instantiation will always result in null values. You may believe there are Messages waiting for you in the first case, but I bet there aren't. Before the conditional loop, print out the number of objects there are and verify the resulting behavior. If you are in a multi-threaded situation, synchronize on the Message queue if necessary to facilitate this. I am betting it works exactly as expected.


My money is on you weren't running the code you thought you were. You mention "running on Glassfish 3.1.1b10 ", so presumably not much in the way of unit testing and therefore the ability to pinpoint where the error is becomes more difficult.

There are a couple possibilities that might possibly make a difference in some bizarre edge case.

  • It makes a subtle change to class loading order, and you do something dodgy in static initialisation. I'm not even sure if it does make a difference to class loading order.
  • 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.


Is it possible for you to provide what consumer oject may be and what does receiveNoWait() may be?

0

精彩评论

暂无评论...
验证码 换一张
取 消