他のスレッドがチャネルをセレクターに登録できるようThread
にするprivateメソッドとSelector
publicメソッドでサブクラス化されています。register(SelectableChannel channel, ...)
ここで答えたように、セレクターの/の間のチャネルのregister()
ブロックなので、セレクターにする必要があります。select()
select(long timeout)
wakeup()
私のスレッドは(中断されない限り)無期限に選択し、実際にはチャネルregister()
が呼び出される前に次の選択に入ることができます。だから私は、最初に起こるsynchronized
ことを確実にするために、ブロック付きの単純なロックを使用すると思いました。register()
コード:(読みやすくするために無関係なコードが削除されました)
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()) {
...
}
}
}
}
}
この単純なロックによりregister()
、スレッドが次の選択ループを続行する前に発生することができます。私がテストした限り、これは想定どおりに機能します。
質問: それはそれを行うための「良い」方法ですか、それともそれに深刻な欠点がありますか?リストまたはキュー(ここで提案されているように)を使用して登録用のチャネルを保存するか、代わりにこのようなより洗練されたロックを使用する方がよいでしょうか?その長所/短所は何でしょうか?それとも「さらに良い」方法はありますか?