一缚陷、概要
前面簡(jiǎn)單介紹了channel的總體設(shè)計(jì)野揪,其中channel里面涉及到一個(gè)核心的組件EventLoop游昼。EventLoop的主要作用是處理channel的IO操作仪缸。
Will handle all the I/O operations for a {@link Channel} once registered.
二涣觉、源碼分析
EventLoop
EventLoop的整體結(jié)構(gòu)
EventLoop的作用:
- 處理channel的I/O操作
- 一個(gè)EventLoop一般會(huì)處理多個(gè)channel
/**
* Will handle all the I/O operations for a {@link Channel} once registered.
*
* One {@link EventLoop} instance will usually handle more than one {@link Channel} but this may depend on
* implementation details and internals.
*
*/
public interface EventLoop extends OrderedEventExecutor, EventLoopGroup {
@Override
EventLoopGroup parent();
}
DefaultEventLoop
DefaultEventLoop是EventLoop的默認(rèn)實(shí)現(xiàn)痴荐。我們看下它的類圖。
DefaultEventLoop類圖
@Override
protected void run() {
for (;;) {
//從隊(duì)列獲取task并執(zhí)行
Runnable task = takeTask();
if (task != null) {
task.run();
//更新最后執(zhí)行時(shí)間
updateLastExecutionTime();
}
//退出
if (confirmShutdown()) {
break;
}
}
}
核心方法是run的這個(gè)方法官册。這里有幾個(gè)問題:
- task是什么時(shí)候被寫入的生兆?
- task到底做了什么事情?
- DefaultEventLoop.run的方法是什么時(shí)候執(zhí)行的膝宁?
帶著這幾個(gè)問題鸦难,我們繼續(xù)往下看。
SingleThreadEventExecutor
我們追蹤DefaultEventLoop的父類员淫,最終找到task添加的方法合蔽。
/**
* Add a task to the task queue, or throws a {@link RejectedExecutionException} if this instance was shutdown
* before.
*/
protected void addTask(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
if (!offerTask(task)) {
reject(task);
}
}
final boolean offerTask(Runnable task) {
if (isShutdown()) {
reject();
}
return taskQueue.offer(task);
}
...
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
//添加task
addTask(task);
if (!inEventLoop) {
//啟動(dòng)線程
startThread();
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
調(diào)用execute方法把task添加到隊(duì)列中。調(diào)用execute的方法有點(diǎn)多介返,我們通過增加日志的方式來看到底添加的task具體是什么東西拴事。
斷點(diǎn)跟蹤
AbstractChannel提交了一個(gè)register事件沃斤。
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
匯總了一下添加的task:
- register
- pipeline的addHandler
- channel的bind事件(綁定地址)
- pipeline.fireChannelActive();(channel激活)
- channel.connect(remoteAddress, connectPromise);(建立連接)
- LocalChannel serve(final LocalChannel peer),最終觸發(fā)pipeline.fireChannelRead(m)方法
三刃宵、總結(jié)
EventLoop顧名思義就是"事件循環(huán)"衡瓶,通過一個(gè)隊(duì)列和一個(gè)線程(loop)實(shí)現(xiàn)了事件的提交和事件的執(zhí)行異步。