NioEventLoop

Summary

NioEventLoop是SingleThreadEventLoop这个抽象类的具体实现、该线程负责注册每一个Channel到特定的Selector上并且可复用该线程。

NioEventLoop在某种意义上可以说是Reactor线程。Netty通过一个线程来处理Selector内的所有事件、业务task、和定时task。

其继承结构拓扑如下图所示

由上面我们可知、因为NioEventLoo实际上就是Reactor线程、它负责的所有IO操作、和定时task、调度task的执行、所以该类的大部分方法都是围着着以上三个功能来定义的方法。

诸如 

/**
 * Registers an arbitrary {@link SelectableChannel}, not necessarily created by Netty, to the {@link Selector}
 * of this event loop.  Once the specified {@link SelectableChannel} is registered, the specified {@code task} will
 * be executed by this event loop when the {@link SelectableChannel} is ready.
 */
public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task)


/**
 * Replaces the current {@link Selector} of this event loop with newly created {@link Selector}s to work
 * around the infamous epoll 100% CPU bug.
 * FIX: JDK空轮询的导致CPU飙升100%的bug
 */
public void rebuildSelector()

 

First

SingleThreadEventLoop、该类是EventLoo的抽象子类、doc解释其将会在一个线程内执行提交过来的所有task。

期内包含了一个ChannelHandle执行时的线程环境、会提供一个线程环境给它、该类即ChannelHandlerInvoker

// 并把当前executor的引用传进去
private final ChannelHandlerInvoker invoker = new DefaultChannelHandlerInvoker(this);

除此之外、此类还实现了EventLoopGroup内定义的register方法的两个重载、详细见下

/**
 * Register a {@link Channel} with an {@link EventLoop} from this {@link EventLoopGroup}. The returned
 * {@link ChannelFuture} will get notified once the registration is completed.
 * <p>
 * It's only safe to submit a new task to the {@link EventLoop} from within a
 * {@link ChannelHandler} once the {@link ChannelPromise} succeeded. Otherwise
 * the task may or may not be rejected.
 * </p>
 */
@Override
public ChannelFuture register(Channel channel) {
	return register(channel, new DefaultChannelPromise(channel, this));
}


/**
 * Register a {@link Channel} with an {@link EventLoop} from this {@link EventLoopGroup}. The provided
 * {@link ChannelPromise} will get notified once the registration is completed. The returned {@link ChannelFuture}
 * is the same {@link ChannelPromise} that was passed to the method.
 * <p>
 * It's only safe to submit a new task to the {@link EventLoop} from within a
 * {@link ChannelHandler} once the {@link ChannelPromise} succeeded. Otherwise
 * the task may or may not be rejected.
 * </p>
 */
@Override
public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
	if (channel == null) {
		throw new NullPointerException("channel");
	}
	if (promise == null) {
		throw new NullPointerException("promise");
	}

	channel.unsafe().register(this, promise);
	return promise;
}

second

SingleThreadEventExecutor、该类是上文的父级抽象类、这个类是个重要的角色、隆重介绍下!

1、这个类、具体定义了线程执行生命周期的具体命名和定义、以及实现方式;

2、此类中抽象方法run、就是大名鼎鼎的Reactor线程启动的入口!该run方法是在孙辈的NioEventLoop中实现;

3、该类实现了java.util.concurrent.Executor的抽象方法execute(Runnable task)。

      execute(Runnable task)方法的调用之处挺多的、这里只具一个例子、

      io.netty.channel.AbstractChannel.AbstractUnsafe#register内的register0方法是封装到Runnable对象内;紧接着会异步触发SingleThreadEventExecutor内的execute方法的调用;这里仅仅举例、Channle的注册后续会详细解析。

3.1 详解SingleThreadEventExecutor#execute(Runnable task)

@Override
public void execute(Runnable task) {
	if (task == null) {
		throw new NullPointerException("task");
	}
    // 判断当前线程是否是Reactor线程
	boolean inEventLoop = inEventLoop();
	if (inEventLoop) {
        // 若是,则将该传进来的task添加进到队列内
		addTask(task);
	} else {
        // 若不是,则说明Reactor线程没有开启、则首先开启Reactor线程;之后再进行task的添加
		startExecution();
		addTask(task);
		if (isShutdown() && removeTask(task)) {
			reject();
		}
	}

	if (!addTaskWakesUp && wakesUpForTask(task)) {
		wakeup(inEventLoop);
	}
}

分解步骤一起看下startExecution方法

private void startExecution() {
	if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {
        // 将线程的生命周期置为已启动
		if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
            // 添加一个定时调度任务、为了清理队列中多余的已经被canceled的任务
			schedule(new ScheduledFutureTask<Void>(
					this, Executors.<Void>callable(new PurgeTask(), null),
					ScheduledFutureTask.deadlineNanos(SCHEDULE_PURGE_INTERVAL), -SCHEDULE_PURGE_INTERVAL));
            // 开始调度
			scheduleExecution();
		}
	}
}

// step1、将当前线程更新为null
// step2、开始执行一个“特殊的Runnable任务”
protected final void scheduleExecution() {
	updateThread(null);
	executor.execute(asRunnable);
}


private final Runnable asRunnable = new Runnable() {
	@Override
	public void run() {
		updateThread(Thread.currentThread());

		// lastExecutionTime must be set on the first run
		// in order for shutdown to work correctly for the
		// rare case that the eventloop did not execute
		// a single task during its lifetime.
		// 这个最后执行时间一定在第一次线程运行的时候要被设置、是为了能够当没有task执行的时候,netty可以按照顺序逐个组关闭它们
		if (firstRun) {
			firstRun = false;
			updateLastExecutionTime();
		}

		try {
			// 这个地方实际上就调用了NioEventLoop中的重写的run()
			SingleThreadEventExecutor.this.run();
		} catch (Throwable t) {
			logger.warn("Unexpected exception from an event executor: ", t);
			cleanupAndTerminate(false);
		}
	}
};

4、此类中含有一个taskQueue的引用、该私有成员变量没有doc;所以我们大胆猜测下

private final Queue<Runnable> taskQueue;

4、1 这个taskQueue的初始化放置到SingleThreadEventExecutor类的构造方法中

/**
 * Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a
 * {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking
 * calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant
 * implementation that does not support blocking operations at all.
 */
protected Queue<Runnable> newTaskQueue() {
	return new LinkedBlockingQueue<Runnable>();
}

pollTask() 

/**
 * @see {@link Queue#poll()}
 */
protected Runnable pollTask() {
	assert inEventLoop();
	for (;;) {
		Runnable task = taskQueue.poll();
		if (task == WAKEUP_TASK) {
			continue;
		}
		return task;
	}
}

takeTask()

/**
 * Take the next {@link Runnable} from the task queue and so will block if no task is currently present.
 * <p>
 * Be aware that this method will throw an {@link UnsupportedOperationException} if the task queue, which was
 * created via {@link #newTaskQueue()}, does not implement {@link BlockingQueue}.
 * </p>
 *
 * @return {@code null} if the executor thread has been interrupted or waken up.
 * 1、如果当前队列内是空的、则会一直阻塞
 * 2、如果我们重写了newTaskQueus()、导致返回的并不是BlockingQueue则该方法则会抛异常
 * 3、如果当前线程被打断、或被唤醒、则返回null
 */
protected Runnable takeTask() {
	assert inEventLoop();
    // 判断类型是否是阻塞队列、若不是、则直接抛出异常
	if (!(taskQueue instanceof BlockingQueue)) {
		throw new UnsupportedOperationException();
	}

    // 获取当前taskQueue的引用
	BlockingQueue<Runnable> taskQueue = (BlockingQueue<Runnable>) this.taskQueue;
	for (;;) {
        // 从定时任务队列scheduledTaskQueue(该队列内的每个task都根据deadline自动排序,返回的是截止时间最靠前的task)内获取task;
		ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
		if (scheduledTask == null) {
			Runnable task = null;
			try {
                //从taskQueue获取任务
				task = taskQueue.take();
				if (task == WAKEUP_TASK) {
					task = null;
				}
			} catch (InterruptedException e) {
				// Ignore
			}
			return task;
		} else {
            // 获取该task的延迟时间
			long delayNanos = scheduledTask.delayNanos();
			Runnable task = null;
			if (delayNanos > 0) {
				try {
                    // 从taskQueue内等待delayNanos纳秒时间;
					task = taskQueue.poll(delayNanos, TimeUnit.NANOSECONDS);
				} catch (InterruptedException e) {
					// Waken up.
					return null;
				}
			}
			if (task == null) {
				// We need to fetch the scheduled tasks now as otherwise there may be a chance that
				// scheduled tasks are never executed if there is always one task in the taskQueue.
				// This is for example true for the read task of OIO Transport
				// See https://github.com/netty/netty/issues/1614
				fetchFromScheduledTaskQueue();
				task = taskQueue.poll();
			}

			if (task != null) {
				return task;
			}
		}
	}

runAllTasks() && runAllTasks(long timeoutNanos)

/**
 * Poll all tasks from the task queue and run them via {@link Runnable#run()} method.
 *
 * @return {@code true} if and only if at least one task was run
 */
protected boolean runAllTasks() {
    // 将scheduledTaskQueue内的task添加进taskQueue
	fetchFromScheduledTaskQueue();
    // 从taskQueue内获取task
	Runnable task = pollTask();
	if (task == null) {
		return false;
	}

	for (;;) {
		try {
			task.run();
		} catch (Throwable t) {
			logger.warn("A task raised an exception.", t);
		}
        // 继续获取task、一直到task为null
		task = pollTask();
		if (task == null) {
            // 此时记录下、最后一个task执行的纳秒时间
			lastExecutionTime = ScheduledFutureTask.nanoTime();
			return true;
		}
	}
}

Thrid

AbstractScheduledEventExecutor该类是上文中的抽象父类;内定义了一个scheduledTaskQueue,默认是scheduledTaskQueue;

内部定义了实时调度api的具体实现;

该类的调度Runnable对象具体实现的类为ScheduledFutureTask、后续会重点讲解该类。

 

Fourth

AbstractEventExecutor 实现EventExecutor接口;并继承子jdk的AbstractExecutorService抽象类

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值