Потоковые последствия AsynchronousByteChannel - PullRequest
3 голосов
/ 12 июля 2011

Javadoc для AsynchronousByteChannel.read () говорит, что операция происходит асинхронно, но что происходит, когда достигается конец потока? Разрешено ли реализации запускать обработчик завершения в том же потоке, который вызвал read ()? С точки зрения реализации, нет причин выполнять эту операцию асинхронно, потому что мы уже знаем результат. Точно так же, если пользователь пытается прочитать в ByteBuffer, где Остальная часть () возвращает 0, мы знаем, что операция чтения должна вернуть 0.

Я спрашиваю, потому что я столкнулся с состоянием гонки в моей собственной реализации AsynchronousByteChannel. Я вызываю обработчик завершения, который вызывает notify () для себя, когда операция завершается. Затем я вызываю следующий код пользователя:

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
  asyncByteChannel.read(handler);
  handler.wait();
}

Обратите внимание, что пользователь предполагает, что обработчик будет уведомлен, когда операция завершится, но поскольку read () фактически вызывает обработчик завершения синхронно, он получает уведомление перед wait (), и последний блокируется навсегда.

Требует ли спецификация от меня обновления CompletionHandler в отдельном потоке, или пользователи должны знать о том, что поток, который вызывает read (), может выполнять некоторые операции синхронно?

Ответы [ 2 ]

1 голос
/ 12 июля 2011

Глядя на http://www.docjar.com/html/api/sun/nio/ch/AsynchronousSocketChannelImpl.java.html, они всегда обновляют CompletionHandler в отдельном потоке, но Future обновляется в том же потоке. Найдите переменную hasSpaceToRead, чтобы найти нужный метод.

Я предполагаю, что их аргументация выглядит примерно так:

  1. Мы создаем будущее, возвращаемое пользователю, поэтому мы никак не можем взаимодействовать с ним (синхронизировать и т. Д.), Прежде чем мы вернем объект.
  2. Пользователь создает CompletionHandler, поэтому у нас нет способа контролировать, что делает реализация (из всего, что мы знаем, мы можем вызвать тупик!). Не рискуйте, запустите обработчик завершения в отдельном потоке.

ОБНОВЛЕНИЕ : Я исправлен. Согласно Invoker.invoke ()"Если текущий поток находится в пуле потоков группы каналов, то обработчик вызывается напрямую, в противном случае он вызывается косвенно."

решено : в соответствии с http://download.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousChannelGroup.html "Если операция ввода-вывода завершается немедленно, а инициирующий поток является одним из объединенных потоков в группе, то обработчик завершения может вызываться напрямую по первоначальной теме. "

1 голос
/ 12 июля 2011

Даже когда обработчик вызывается в другом потоке, нет гарантии, что он будет вызван после возврата метода read, т. Е. После запуска wait().(Хорошо, блокировка синхронизации, кажется, гарантирует это.)

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

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
   asyncByteChannel.read(handler);
   while(!handler.finished) {
     handler.wait();
   }
}

... и ваш обработчик установитпеременная finished в true.

...