Что происходит с экземпляром ServerSocket, заблокированным внутри accept (), когда я удаляю все ссылки на него? - PullRequest
1 голос
/ 01 апреля 2010

В многопоточном приложении Java я просто обнаружил странно выглядящую ошибку, осознав, что то, что, похоже, происходит, было следующим:

  • один из моих объектов хранил ссылку на экземпляр ServerSocket
  • при запуске один поток в своем основном цикле в run() вызовет accept() в сокете
  • пока сокет все еще ожидает соединения, другой поток попытается перезапустить компонент
  • при некоторых условиях процесс перезапуска пропустил последовательность очистки до того, как достиг последовательности инициализации
  • в результате ссылка на сокет была перезаписана новым экземпляром, который затем не смог bind() больше
  • сокет, который блокировал внутри accept(), больше не был доступен, поэтому единственным способом избавиться от него было полное отключение и перезапуск приложения.

Что заставляет меня задуматься: а) Блокирующий вызов препятствует или мешает GC каким-либо образом? б) Если ServerSocket получит GCed, сделает ли он снова доступным сокет?

В целом, каковы хорошие практики, которым я могу следовать, чтобы избежать ошибок такого типа? Например, я выучил здесь два урока:

  • Вся логика жизненного цикла (т. Е. Уровень компонента, циклы инициализации, запуска, остановки, очистки) должна быть синхронизирована. Я полагаю, это довольно очевидно, но я не воспринял это достаточно серьезно.
  • Логика жизненного цикла должна быть максимально простой, чтобы избежать моей проблемы неочевидных путей кода, пропускающих этапы очистки или инициализации.

Ответы [ 3 ]

2 голосов
/ 02 апреля 2010

Чтобы ответить на вопрос в заголовке: с ServerSocket ничего не случится. До сих пор есть ссылка на ваш ServerSocket из стека вызовов потока, блокирующего вызов accept (); эта ссылка не позволит ServerSocket иметь право на сбор мусора.

2 голосов
/ 01 апреля 2010

Вы всегда должны close() ServerSocket, если вы хотите предсказуемую очистку.

Тот факт, что все ссылки были отброшены, означает лишь то, что он доступен для GC, а не для того, чтобы он когда-либо был в GC. При наличии доступной памяти процесса в мегабайтах существует очень небольшая вероятность того, что отдельный объект будет подвергнут сборке мусора за короткий период.

Обычно вы звоните close из потока обслуживания. Во многих серверных приложениях он вызывается из ловушки завершения работы.

0 голосов
/ 31 марта 2011

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

Я создал общий компонент под названием SocketServer, который прослушивает порт и принимает подключения. Как только соединение установлено, он передает объект Socket классу, реализующему SocketHandler, в отдельном потоке.

SocketHandler имеет такие методы, как onSocket (Сокет-сокет); в этом(); уничтожить ();

SocketServer имеет такие методы, как StartServer (); stopServer ();

Свойства сервера сокетов, такие как порт и экземпляр SocketHandler, можно легко настроить с помощью Spring.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...