NIO Selector: Como registrar corretamente o novo canal ao selecionar
Eu tenho uma subclasseThread
com um privadoSelector
e um públicoregister(SelectableChannel channel, ...)
método que permite que outros segmentos registrem canais para o seletor.
Como respondidoAqui, o canalregister()
blocos durante o seletorselect()
/ select(long timeout)
então precisamoswakeup()
o seletor.
Meu thread seleciona indefinidamente (a menos que seja interrompido) e ele realmente consegue entrar no próximo select antes do canalregister()
é chamado. Então eu pensei em usar um cadeado simplessynchronized
blocos para garantir aregister()
acontece primeiro.
O código: (código irrelevante removido para legibilidade)
public class SelectorThread extends Thread {
...
public void register(SelectableChannel channel, Attachment attachment) throws IOException {
channel.configureBlocking(false);
synchronized (this) { // LOCKING OCCURS HERE
selector.wakeup();
channel.register(selector,
SelectionKey.OP_READ,
attachment);
}
}
@Override
public void run() {
int ready;
Set<SelectionKey> readyKeys;
while (!isInterrupted()) {
synchronized (this) {} // LOCKING OCCURS HERE
try {
ready = selector.select(5000);
} catch (IOException e) {
e.printStackTrace();
continue;
}
if (ready == 0) {
continue;
}
readyKeys = selector.selectedKeys();
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
...
}
}
}
}
}
Este bloqueio simples permiteregister()
acontecer antes que o segmento continue com o próximo loop de seleção. Tanto quanto eu testei, isso funciona como suposto.
Questões: É uma maneira "boa" de fazê-lo ou há alguma desvantagem séria nisso? Seria melhor usar uma lista ou fila (como sugeridoAqui) para armazenar canais para registro, ou um bloqueio mais sofisticado comoisto em vez de? Quais seriam os prós / contras disso? Ou existem maneiras "ainda melhores"?