PrintWriter ожидает сброса()

Я пишу многопоточный сервер сокетов. Я использую ServerSocketChannel nio для приема соединений. Затем я читаю и пишу (в отдельных потоках) в socketChannel, используя bufferedreader и средство записи на печать. Проблема в том, что PrintWriter блокируется и ждет команды flush(). Он блокирует поток до тех пор, пока BufferedReader не получит данные.


person JBLew    schedule 20.02.2011    source источник


Ответы (2)


Это указывает на то, что приемник медленно читает. Вот как работает блокировка ввода-вывода. Если вам нужен неблокирующий ввод-вывод, вы уже на пути к этому, поскольку уже используете NIO. Хотя я вообще не вижу смысла использовать NIO в режиме блокировки.

person user207421    schedule 20.02.2011
comment
Использование неблокирующего режима решило эту проблему. Сейчас я читаю с помощью socketChanne.read() и пишу с помощью socketChannel.write(). - person JBLew; 21.02.2011
comment
Это просто перемещает проблему. Ваши записи вернут ноль, если ваш вызов flush() заблокирован. Таким образом, буфер не очищается, поэтому вам некуда поместить данные, которые вы хотите записать, поэтому вы должны прекратить это делать. Или потерять данные. - person user207421; 22.02.2011

Как говорит @EJP, в основном так работает блокировка ввода-вывода. Действительно, эта проблема присуща любой архитектуре, где у вас есть производитель и потребитель. Если производитель производит материал (в данном случае строки вывода текста) быстрее, чем потребитель может его потреблять, то производитель в конечном итоге должен заблокировать.


Как вы можете решить эту проблему? Сначала немного общего.

Если производитель производит товар быстрее, чем потребитель потребляет его в долгосрочной перспективе, вы находитесь между молотом и наковальней. Вы должны либо уменьшить скорость производства производителя, ускорить скорость потребления потребителя, либо уменьшить накладные расходы в конвейере с тем же эффектом. Ничто другое не работает.

Если несоответствие скорости носит временный характер, вы можете «замазать трещины», добавив дополнительную буферизацию в конвейер. Если соединение между ними имеет некоторую буферную способность, вы можете увеличить ее. В качестве альтернативы вы можете добавить дополнительную буферизацию на стороне производителя или потребителя.


Вот некоторые вещи, которые могут помочь в вашем конкретном случае.

  • Уменьшите количество материалов, которые вы пишете в потоках производителей.

  • Выполняйте меньше работы в потребительских потоках или профилируйте/настройте их, чтобы они выполняли работу быстрее.

  • Не используйте сокет для связи между двумя потоками в одной JVM. Если вы можете это организовать, используйте пару Java PipeInputStream/PipeOutputStream или сверните свой собственный эквивалент. (Если вы используете сокет, чтение и запись включают системные вызовы, копирование данных в буферы ядра и из них и так далее.)

  • В случае, когда связь должна выходить за пределы JVM, убедитесь, что вы используете Buffered* оболочки для базовых потоков, чтобы уменьшить количество системных вызовов, выполняемых при чтении/записи.

person Stephen C    schedule 20.02.2011
comment
Я не использую потоки для связи между потоками. Это приложение telnet. - person JBLew; 21.02.2011
comment
@JBLew ... вы не сказали, находятся ли клиент и сервер telnet в одной и той же JVM или нет. - person Stephen C; 21.02.2011