API должен работать как описано. Read вернет -1, когда соединение сокета будет закрыто. Это не то же самое, что «конец сообщения». Соединение может быть закрыто по тайм-ауту, и я отмечаю, что вы сказали, что клиент ожидал «долгое время».
Я также отмечаю, что вы работаете с конкретным учебником. Код клиента в этом руководстве специально закрывает соединение после получения ответа и открывает новый для каждой отправки. Чтобы остановить это, вам придется внести большие изменения в дизайн клиентского кода.
Когда я запускаю сервер nio из этого учебника с клиентом, который не закрывает соединение, поведение такое, как описывает API - серверный поток ждет в Selector.select (), пока клиент спит между отправкой сообщений.
Таким образом, мой ответ заключается в том, что вы, вероятно, используете клиент, который закрывает соединения, и если не «долгое время», которое вы ожидаете, может привести к тому, что сеть закроет соединения для вас. Учитывая поведение, которое вы описываете, я почти уверен, что это первое.