Nil*_*esh 14 java multithreading deadlock nio
我有一个基本问题.SelectableChannel的寄存器方法为何以及如何阻止调用.让我提供一个场景.
我在类Register中创建了一个Selector对象,如下所示.
private static Selector selector = Selector.open();
Run Code Online (Sandbox Code Playgroud)
我在同一类(寄存器)中也有一个方法用选择器注册通道.
public static SelectionKey registerChannel(SelectableChannel channel, int ops)
throws IOException {
channel.configureBlocking(false);
return channel.register(selector, ops);
}
Run Code Online (Sandbox Code Playgroud)
还有另一个名为Request的类,它具有从通道,进程和调用方法中读取数据以注册通道的方法.
selectonKey = Register.register(socketChannel, SelectionKey.OP_READ);
Run Code Online (Sandbox Code Playgroud)
在这一点上,线程被阻塞,没有提供它正在等待的线索.我已经确认选择器已打开.请帮助我了解如何解决此问题.我可以释放任何锁吗?
任何输入将不胜感激.
添加到我描述的内容中.进一步的测试显示,如果从同一个线程调用Register.register方法,它可以注册,但在此之后,如果其他一些线程尝试调用该方法,则线程不会继续前进.
Dar*_*ron 36
这是大多数NIO实现的基本功能,这些功能在文档中并不明显.
您需要从正在进行选择的相同线程进行所有寄存器调用,否则将发生死锁.通常这是通过提供写入的注册/注销/兴趣更改队列来完成的,然后调用selector.wakeup().当选择线程唤醒时,它会检查队列并执行任何请求的操作.
Kev*_*ron 11
您需要使用锁并手动同步.
在运行选择器循环的同一个线程中有一个ReentrantLock:
final ReentrantLock selectorLock = new ReentrantLock();
Run Code Online (Sandbox Code Playgroud)
然后,当您需要使用选择器注册时,执行以下操作:
selectorLock.lock();
try {
selector.wakeup();
socketChannel.register(selector, ops);
} finally {
selectorLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)
最后,在你的循环中你正在调用accept(),这样的事情:
selectorLock.lock();
selectorLock.unlock();
selector.select(500);
Run Code Online (Sandbox Code Playgroud)
然后继续其余的逻辑.
此构造register()通过确保select()在相应wakeup()和register()调用之间不存在另一个来保证调用不会阻塞.
您是否尝试过打印程序中所有线程的堆栈跟踪(kill -QUIT在 Unix 中使用或在 Windows 中使用 Ctrl+Break 或使用该jstack实用程序)?
AbstractSelectableChannel包含一个configureBlocking需要register同步的锁。该锁也可以通过该方法访问blockingLock(),因此另一个线程可能持有该锁,导致您的寄存器调用无限期地阻塞(但如果没有堆栈跟踪,则很难判断)。