Почему Java Object Stream возвращает один и тот же объект каждый раз, когда я вызываю readObject?

Простите псевдокод - мои беспроводные сети отключены, и я не могу скопировать код с моего автономного компьютера на StackExchange на данный момент.

У меня есть два java-приложения, подключаемые через java.net. * сокеты. Я пытаюсь передать объекты "Сообщение" от одного к другому с помощью потоков объектных/выходных данных.

Вот что я делаю:

Class Message implements Serializable
{
  String text
  int data
     public Message(String txt, int dat)
     {
      this.text = txt;
      this.data = dat;
     }
     string toString()
     {
      return text + " " + data;
     }
}

Сервер

Сервер имеет очередь с именем Outbox

for(int i = 0; i < 1000; i++)
 { 

 Message adding = new Message("Hello!",i);
 Outbox.add(temp)
 Message temp =     Outbox.poll();
 out.writeObject(temp);
  system.out.println(temp)
 }

Client

for(int i = 0; i < 1000; i++)
{
  Message temp;
  temp = in.readObject()
  system.out.println(temp)
}

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

Сервер

Hello 0
Hello 1
Hello 2
Hello 3...

Client

Hello 0
Hello 0
Hello 0
Hello 0...

Итак, похоже, что объекты сообщения читаются, но не удаляются из потока.

Как я могу очистить потоки и синхронизировать их, как ожидалось?

Ответ 1

классической причиной этой проблемы является отправка одной и той же ссылки объекта несколько раз. поток Object impls сохраняет идентификатор ссылки объекта, а на принимающей стороне вы получите тот же объект обратно на каждый вызов readObject() (даже если вы изменили объект на стороне отправки!). ваш псевдокод корректен, однако вопрос в том, правильно ли он отражает ваш фактический код.

если ваша проблема является справочной проблемой, вы можете решить проблему путем отправки разных экземпляров объекта каждый раз или с помощью writeUnshared() и/или вызова reset() между каждым вызовом writeObject(). использование writeUnshared() заставит основной объект быть экземпляром нового объекта на принимающей стороне, но другие объекты, на которые может ссылаться этот объект, могут по-прежнему являться общими ссылками. с другой стороны, вызов reset() приведет к очистке всех кэшированных объектов на принимающей стороне, поэтому все ссылки на объекты на принимающей стороне будут новыми ссылками. который лучше всего управляет данными по проводу, зависит от вашего использования, но для долговременных потоков всегда полезно периодически вызывать reset(), так как это освободит память, которая со временем будет нарастать (это является обычной, но тонкой "утечкой памяти" при использовании потоков объектов).