одновременная обработка java.nio.channels.Selector - PullRequest
4 голосов
/ 08 января 2010

Я работаю с java.nio.channels.Selector и хочу создать отдельный поток для каждого selectedKey, который готов для чтения / записи / принятия, но я хочу убедиться, что один и тот же сокет никогда не обрабатывается двумя разными потоками одновременно. что было бы лучшим способом сделать это? я думал отменить каждый selectedKey перед созданием потока, который будет обрабатывать его сокет, и перерегистрацией сокета в селектор, как только поток завершил свою жизнь, но я не уверен, насколько это будет эффективно ....

Ответы [ 2 ]

9 голосов
/ 08 января 2010

Есть действительно хорошая презентация Дуга Ли о масштабируемом вводе / выводе в Java, которую я использовал при создании своего сервера. Я использую следующий подход:

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

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

1 голос
/ 08 января 2010

Я думаю, что создание отдельного потока для каждого сокета может оказаться слишком большим. Кроме того, создание нового Thread довольно дорого по времени выполнения. Вы должны ограничить количество активных потоков и ограничить создание новых потоков с помощью пула потоков. java.util.concurrent.Executors предлагает возможность создания фиксированного пула потоков. Подробности в http://java.sun.com/docs/books/tutorial/essential/concurrency/pools.html.

Если вы хотите защитить сокеты от одновременного попадания в несколько потоков, я бы рассмотрел самое простое исключение: блокировка объекта сокета. Могут быть более эффективные стратегии, но, вероятно, не более простые или более надежные.

Обновление

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

Две альтернативы, которые я могу придумать:

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

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

...