在Netty源码中很多地方都会调用一个叫做inEventLoop()的方法, 这个方法的作用是啥呢?
在NioEventLoop中封装了一个线程, 这个线程我们叫它IO线程.
private volatile Thread thread;
这个IO线程就是用来处理客户端的连接事件, 读写事件, 还有一个重要的事情也是由这个IO线程去做的, 是啥呢? 就是处理队列中的任务. 没错, 每个NioEventLoop都有一个队列, 这个队列是在创建NioEventLoop时被初始化
taskQueue = newTaskQueue(this.maxPendingTasks);
@Override
protected Queue newTaskQueue(int maxPendingTasks) {
return maxPendingTasks == Integer.MAX_VALUE ? PlatformDependent.newMpscQueue()
: PlatformDependent.newMpscQueue(maxPendingTasks);
}
这个队列的具体实现简单说就是多个生产者单个消费者, 要不为啥叫Mp(producer)s(single)c(consumer)呢.
现在看来就比较明朗了, 其他的线程, 也就是多个生产者, 如果需要进行读写操作, 就把读写操作封装成任务放在这个队列中, 然后由这个NioEventLoop封装的IO线程去消费. 当然这个队列的设计是线程安全的, 否则就出问题了.
那么假如现在有一个线程, 它咋知道我是该主动去执行读写操作, 还是应该把自己的读写操作封装成任务放在队列中呢? 那么它就会去调用一下inEventLoop()方法, 这个方法会返回一个boolean值告诉它. 其实这个方法的实现很简单
@Override
public boolean inEventLoop() {
return inEventLoop(Thread.currentThread());
}
@Override
public boolean inEventLoop(Thread thread) {
return thread == this.thread;
}
从源码中可以看出来, 它就是拿当前线程和之前创建NioEventLoop时绑定的那个IO线程进行判断, 如果是一样的, 说明此线程就是绑定的IO线程, 可以执行读写操作, 如果不一样, 那么说明是其他线程, 就要把读写操作封装成任务放在队列中, 由绑定的那个IO线程去执行.
这也是Netty设计的异步串行无锁化. 在Netty中线程之间不用同步控制, 可以做到线程安全.