Необычное поведение Java - почему это работает? - PullRequest
9 голосов
/ 13 июля 2011

Я обнаружил интересное поведение ... Я не могу решить, является ли это ошибкой или некомпетентностью, но сейчас склоняюсь к некомпетентности.

Этот код не войдет в цикл, даже если ожидают сообщения:

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

Этот код вводит цикл, обратите внимание на нулевое назначение:

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

Этот код работает на Glassfish 3.1.1b10 HotSpot 1.6_26 на Windows 32bit. Я не могу придумать объяснения, почему первый блок не работает!

РЕДАКТИРОВАТЬ / ОБНОВИТЬ 13 июля 2011 года:

Сначала я начал останавливать домен Glassfish и удалять его между развертываниями по запросу, и это все еще происходит:)

Во-вторых, я не могу выполнить синхронизацию на получателе или получателе, так как это код Java EE. Но я могу заверить, что сообщения доступны. Там около 500 из них доступны без потребителей. Фактически, создание QueueBrowser говорит мне, что сообщения доступны!

В-третьих, эта программа печатает "РАБОТАЕТ!" каждый раз!!! ARGH !!!

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 ]

3 голосов
/ 13 июля 2011

Как сказал Райан, это похоже на состояние гонки. Байт-коды для обоих кодов одинаковы, за исключением дополнительного «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". Я предпочитаю «получать (smallTimeout)», чтобы избежать переполнения буфера или чего-то подобного.

1 голос
/ 13 июля 2011

Для меня это похоже на состояние гонки.Объявление объектов без создания экземпляров всегда приведет к нулевым значениям.Вы можете поверить, что в первом случае вас ждут Сообщения, но я уверен, что их нет.Перед условным циклом распечатайте количество объектов и проверьте полученное поведение.Если вы находитесь в многопоточной ситуации, при необходимости выполните синхронизацию в очереди сообщений.Держу пари, что все работает именно так, как и ожидалось.

0 голосов
/ 13 июля 2011

Можете ли вы указать, какой может быть потребительский объект и что может иметь функция receiveNoWait ()?

0 голосов
/ 13 июля 2011

Мои деньги на том, что вы не выполняете код, который вы думали.Вы упомянули «запуск на Glassfish 3.1.1b10», так что, вероятно, не так много, как в модульном тестировании, и, следовательно, возможность точно определить, где ошибка, становится более трудной.

Есть пара возможностей, которые могут сделатьразница в каком-то странном краевом случае.

  • Это вносит небольшие изменения в порядок загрузки классов, и вы делаете что-то хитрое в статической инициализации.Я даже не уверен, имеет ли это значение для порядка загрузки классов.
  • Назначение null перекрывает ссылку на стек, которая позволяет собирать мусор, ссылающийся на объект, которыйиспользуется со слабой / мягкой / фантомной / финализаторной ссылкой или, возможно, просто изменяет время выделения памяти и нарушает состояние гонки.
...