NioEventLoop处理io的一些操作方法
io.netty.channel.nio.NioEventLoop#run
/**
* 启动服务 轮询selector
*/
@Override
protected void run() {
for (;;) {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.SELECT:
// 重置 wakenUp 标记为 false
//wakenUp标识当前selector是否是唤醒状态
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
//处理轮询到的key
processSelectedKeys();
} finally {
// Ensure we always run tasks.
//启动task
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
...
}
}
这个run方法是在NioEventLoop线程启动的时候调用的,这里面主要:
- 轮询准备好的key
- 处理轮训出来的key
- 运行task任务
io.netty.channel.nio.NioEventLoop#select
/**
* 轮询selector方法
* @param oldWakenUp
* @throws IOException
*/
private void select(boolean oldWakenUp) throws IOException {
Selector selector = this.selector;
try {
int selectCnt = 0;
long currentTimeNanos = System.nanoTime();
//delayNanos(currentTimeNanos)计算当前定时任务队列第一个任务的延迟时间
//select的时间不能超过selectDeadLineNanos这个时间
long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);
for (;;) {
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
if (timeoutMillis <= 0) {
//如果超时 并且第一次轮询
//那么就再进行一次非阻塞的select 然后break结束轮询
if (selectCnt == 0) {
selector.selectNow();
selectCnt = 1;
}
break;
}
//nioEventLoop有任务在进行,那么就进行一次非阻塞的select 然后break结束轮询
if (hasTasks() && wakenUp.compareAndSet(false, true)) {
selector.selectNow();
selectCnt = 1;
break;
}
//定时任务为空 截止时间没到,进行阻塞select
int selectedKeys = selector.select(timeoutMillis);
selectCnt ++;
if (selectedKeys != 0 || oldWakenUp