上文提到了Netty创建Nio线程的过程,本文将更深入的了解EventLoop
EventLoop
- 事件循环
- 通过不停的轮训事件集合,去处理所有的事件
NioEventLoopGroup里面的线程创建器
传入一个默认线程工厂 //底层实现了自己的ThreadFactory,继承于juc的ThreadFactory 每次执行任务都会新增一个线程实体
- 线程命名为NioEventLoop - 1-xx(第一个NioeventLoop)
class Test {
public static void main(String[] args) {
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
}
public static String toPoolName(Class<?> poolType) {
ObjectUtil.checkNotNull(poolType, "poolType");
String poolName = StringUtil.simpleClassName(poolType);//NioEventLoop
switch (poolName.length()) {
case 0:
return "unknown";
case 1:
return poolName.toLowerCase(Locale.US);
default:
if (Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))) {
return Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1);//nioEventLoop
} else {
return poolName;
}
}
}
public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
ObjectUtil.checkNotNull(poolName, "poolName");
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
throw new IllegalArgumentException(
"priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
}
prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon;
this.priority = priority;
this.threadGroup = threadGroup;
}
}
ThreadPerTaskExecutor
线程执行器
class ThreadPerTaskExecutor {
@Override
public void execute(Runnable command) {
threadFactory.newThread(command).start();
}
@Override
public Thread newThread(Runnable r) {
//名字就是nioevent-group
Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
try {
if (t.isDaemon() != daemon) {
t.setDaemon(daemon);
}
if (t.getPriority() != priority) {
t.setPriority(priority);
}
} catch (Exception ignored) {
// Doesn't matter even if failed to set.
}
return t;
}
protected Thread newThread(Runnable r, String name) {
return new FastThreadLocalThread(threadGroup, r, name);
}
//netty自己封装的thread
//把threadLocal包装了一下
public FastThreadLocalThread(ThreadGroup group, Runnable target, String name) {
super(group, FastThreadLocalRunnable.wrap(target), name);
cleanupFastThreadLocals = true;
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
}
MpscQueue
创建线程选择器
调用chooser.next方法寻找下一个线程
- 判断eventLoop数组是否是二的倍数
- 是的话创建一个二倍数优化的chooser
- 优化的chooser用与操作
class Test {
private final EventExecutorChooserFactory.EventExecutorChooser chooser;
Test() {
chooser = chooserFactory.newChooser(children);
}
//判断executor 是否是二的倍数
//是的话创建一个两倍的chooser
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
@Override
public EventExecutor next() {
return chooser.next();
}
@Override
public EventExecutor next() {
//index++然后异或length-1
return executors[idx.getAndIncrement() & executors.length - 1];
}
@Override
public EventExecutor next() {
return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];
}
}
NioeventLoop的启动
在bind方法中到dobind0 然后由eventLoop去execute执行 例: SingleThreadEventExecutor的实现
- 先判断是否是当前线程
- 是的话提交一个任务
- 不是的话新建一个线程执行任务
class Bind {
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
channel.eventLoop().execute(() -> {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
});
}
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
//判断线程是否是当前线程
boolean inEventLoop = inEventLoop();
if (inEventLoop) {
addTask(task);
} else {
//否则新建一个线程
startThread();
addTask(task);
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
}
如何启动一个线程?
双检cas设置线程状态 先保存当前的线程 然后让NioeventLoop执行
class Test {
private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false;
try {
doStartThread();
success = true;
} finally {
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (; ; ) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
// Run all remaining tasks and shutdown hooks. At this point the event loop
// is in ST_SHUTTING_DOWN state still accepting tasks which is needed for
// graceful shutdown with quietPeriod.
for (; ; ) {
if (confirmShutdown()) {
break;
}
}
// Now we want to make sure no more tasks can be added from this point. This is
// achieved by switching the state. Any new tasks beyond this point will be rejected.
for (; ; ) {
int oldState = state;
if (oldState >= ST_SHUTDOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTDOWN)) {
break;
}
}
// We have the final set of tasks in the queue now, no more can be added, run all remaining.
// No need to loop here, this is the final pass.
confirmShutdown();
} finally {
try {
cleanup();
} finally {
FastThreadLocal.removeAll();
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.countDown();
int numUserTasks = drainTasks();
if (numUserTasks > 0 && logger.isWarnEnabled()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + numUserTasks + ')');
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
}
NioeventLoop执行
- 无限循环
- select轮询检查是否有io事件
- 处理io事件
- 处理异步任务队列
Select 方法执行逻辑
- deadline 以及任务穿插逻辑处理
- 阻塞式select
- 避免jdk空轮训
class Test {
public void test() {
case SelectStrategy.SELECT:
// 获得下一个任务完成时间
long curDeadlineNanos = nextScheduledTaskDeadlineNanos();
if (curDeadlineNanos == -1L) {
curDeadlineNanos = NONE; // nothing on the calendar
}
//下个线程唤醒时间设置
nextWakeupNanos.set(curDeadlineNanos);
try {
//没有任务的话,轮询selector
if (!hasTasks()) {
strategy = select(curDeadlineNanos);
}
} finally {
//延迟启动,避免空轮训
nextWakeupNanos.lazySet(AWAKE);
}
}
}
processSelectedKeys执行逻辑
主要是处理io事件
- selected keySet优化 成数组,优于hashset (SelectedSelectionKeySet)
- processSelectedKeysOptimized()处理io时间
class Test {
private void processSelectedKeysOptimized() {
for (int i = 0; i < selectedKeys.size; ++i) {
final SelectionKey k = selectedKeys.keys[i];
//取出对应的key,在openSelector中赋值
selectedKeys.keys[i] = null;
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (needsToSelectAgain) {
// null out entries in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
selectedKeys.reset(i + 1);
selectAgain();
i = -1;
}
}
}
}
runAllTasks()执行逻辑
- task的分类和添加
- 普通任务队列(taskQueue),定时任务队列(schedule)(判断是否是外部线程发起,是的话就新建个线程添加进定时任务队列)(非线程安全Queue)
- 任务的聚合
class 任务的聚合 {
private boolean fetchFromScheduledTaskQueue() {
//判断定时任务是否为空
if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
return true;
}
//获取时间
long nanoTime = AbstractScheduledEventExecutor.nanoTime();
for (; ; ) {
//任务比较的是截止时间,截止时间相同就比较id
Runnable scheduledTask = pollScheduledTask(nanoTime);
if (scheduledTask == null) {
return true;
}
//添加进普通的任务队列
if (!taskQueue.offer(scheduledTask)) {
// 添加失败就塞回定时任务
scheduledTaskQueue.add((ScheduledFutureTask<?>) scheduledTask);
return false;
}
}
}
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
Runnable task = pollTaskFrom(taskQueue);
if (task == null) {
return false;
}
for (; ; ) {
safeExecute(task);
task = pollTaskFrom(taskQueue);
if (task == null) {
return true;
}
}
}
}