サブクラスThread
にプライベートSelector
と公開register(SelectableChannel channel, ...)
メソッドがあり、他のスレッドがチャンネルをセレクタに登録できるようにしています。NIOセレクタ:選択時に新しいチャンネルを正しく登録する方法
としては中にhere、チャネルのregister()
ブロックに答えセレクタのselect()
/select(long timeout)
ので、我々は、セレクタをwakeup()
する必要があります。
スレッドが中断しない限り無期限に選択し、チャネルのregister()
が呼び出される前に実際に次の選択に入ることを管理します。だから私はブロックで単純なロックを使用して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()
が起こることを可能にします。私がテストした限り、これは想定どおりに動作します。
質問: これは「良い」方法ですか、それとも深刻な欠点がありますか?登録のためのチャンネルやthisのようなもっと洗練されたロックを格納するために、リストやキュー(推奨のhere)を使用する方が良いでしょうか?それの長所/短所は何ですか?それとも「もっと良い」方法がありますか?
select()が呼び出されているときにセレクタにチャネルを登録しているときに[Javaスレッドブロックの重複が可能です。どうすればいいですか?](https://stackoverflow.com/questions/1057224/java-thread-blocks-while-registering-channel-with-selector-while-select-is-cal) – Flow