Selector NIO: cómo registrar correctamente el nuevo canal mientras se selecciona
Tengo una subclaseThread
con un privadoSelector
y un publicoregister(SelectableChannel channel, ...)
Método que permite a otros hilos registrar canales al selector.
Como se respondeaquí, el canalregister()
bloques durante el selectorselect()
/ select(long timeout)
por lo que necesitamoswakeup()
el selector
Mi hilo selecciona de forma indefinida (a menos que se interrumpa) y realmente logra ingresar a la siguiente selección antes del canalregister()
se llama. Así que pensé que uso un simple bloqueo consynchronized
bloques para asegurar laregister()
pasa primero
El código: (código irrelevante eliminado para facilitar la lectura)
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 simple bloqueo permiteregister()
que suceda antes de que el hilo continúe con el siguiente bucle de selección. Por lo que he probado, esto funciona como se supone.
Preguntas: ¿Es esa una "buena" forma de hacerlo o hay algunas desventajas serias en eso? ¿Sería mejor usar una Lista o Cola (como se sugiereaquí) para almacenar canales de registro, o un bloqueo más sofisticado comoesta ¿en lugar? ¿Cuáles serían los pros / contras de eso? ¿O hay formas "incluso mejores"?