Netty源码(五)之SingleThreadEventExecutor.this.run()的过程

上篇博客已经讲完了bind()方法,但是bind()方法中还有两个部分没有讲,一个是dobind0()方法,还有一个就是在执行register()的方法的时候开启了一个线程执行register0()方法,这个线程开启的方法就是我们主要讲的。下面就让我们代码重现吧。具体的代码如下所示:

	public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected abstract class AbstractUnsafe implements Unsafe {
    @Override
    public final void register(EventLoop eventLoop, final ChannelPromise promise) {
      if (eventLoop == null) {
        throw new NullPointerException("eventLoop");
      }
      if (isRegistered()) {
        promise.setFailure(new IllegalStateException("registered to an event loop already"));
        return;
      }
      if (!isCompatible(eventLoop)) {
        promise.setFailure(
          new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
        return;
      }
      //promise=DefaultChannelPromise
      //eventLoop=SingleThreadEventLoop
      //this.eventLoop=NioEventLoop==>SingleThreadEventLoop.this
      AbstractChannel.this.eventLoop = eventLoop;
      //他们最终都调用了register0   eventLoop.inEventLoop()的作用?
      if (eventLoop.inEventLoop()) {
        register0(promise);
      } else {
        try {
          eventLoop.execute(new Runnable() {
            @Override
            public void run() {
              System.out.println("register0");
              register0(promise);
            }
          });
        } catch (Throwable t) {
          logger.warn(
            "Force-closing a channel whose registration task was not accepted by an event loop: {}",
            AbstractChannel.this, t);
          closeForcibly();
          closeFuture.setClosed();
          safeSetFailure(promise, t);
        }
      }
    }
  }
}

上面的代码会执行到eventLoop.execute()方法,我们继续重现。具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
	@Override
  public void execute(Runnable task) {
    if (task == null) {
      throw new NullPointerException("task");
    }
    //调用doStartThread方法启动事件轮询后此方法返回true
    boolean inEventLoop = inEventLoop();
    //将任务加入线程队列
    addTask(task);
    //判断当前执行此任务的线程是否是SingleThreadEventExecutor
    if (!inEventLoop) {
      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)) {
      //唤醒阻塞的selector
      wakeup(inEventLoop);
    }
  }
}

上面走来会将刚才的register0()方法添加到任务队列taskQueue中去,然后判断当前执行此任务的线程是否是SingleThreadEventExecutor,很明显是,这个就开始调用startThread();方法来启动线程了。具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
	private void startThread() {
    if (state == ST_NOT_STARTED) {
      //尝试将ST_NOT_STARTED设置为ST_STARTED
      if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
        boolean success = false;
        try {
          doStartThread();
          success = true;
        } finally {
          //如果执行doStartThread()出现异常  将STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED回滚
          if (!success) {
            STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
          }
        }
      }
    }
  }
}

上面的代码直接通过CAS操作将线程的状态从ST_NOT_STARTED改成ST_STARTED,然后调用doStartThread();具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  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.
            for (;;) {
              if (confirmShutdown()) {
                break;
              }
            }
          } finally {
            try {
              cleanup();
            } finally {
              // Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
              // the future. The user may block on the future and once it unblocks the JVM may terminate
              // and start unloading classes.
              // See https://github.com/netty/netty/issues/6596.
              FastThreadLocal.removeAll();
              STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
              threadLock.countDown();
              if (logger.isWarnEnabled() && !taskQueue.isEmpty()) {
                logger.warn("An event executor terminated with " +
                            "non-empty task queue (" + taskQueue.size() + ')');
              }
              terminationFuture.setSuccess(null);
            }
          }
        }
      }
    });
  }
}

上面的executor.execute();通过线程工厂启动了一个线程去执行下面的代码,我们今天主要分析就是下面的这段代码。这个时候将当前线程赋值给属性thread这个开启线程中最核心的方法就是SingleThreadEventExecutor.this.run();也是我们今天重点要讲的方法,我们继续跟进相应的代码,具体的代码如下:

public final class NioEventLoop extends SingleThreadEventLoop {
	//事件循环
  @Override
  protected void run() {
    for (;;) {
      try {
        try {
          //hasTasks()  若taskQueue or  tailTasks任务队列中有任务  返回false  没有则返回true
          //有任务返回selectNow的返回值   没任务返回-1
          switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
            case SelectStrategy.CONTINUE:
              continue;
            case SelectStrategy.BUSY_WAIT:
              // fall-through to SELECT since the busy-wait is not supported with NIO
            case SelectStrategy.SELECT:
              //首先轮询注册到reactor线程对应的selector上的所有的channel的IO事件
              //wakenUp 表示是否应该唤醒正在阻塞的select操作,netty在每次进行新的loop之前,都会将wakeUp 被设置成false,标志新的一轮loop的开始
              select(wakenUp.getAndSet(false));
              if (wakenUp.get()) {
                selector.wakeup();
              }
              // fall through
            default:
          }
        } catch (IOException e) {
          // If we receive an IOException here its because the Selector is messed up. Let's rebuild
          // the selector and retry. https://github.com/netty/netty/issues/8566
          rebuildSelector0();
          handleLoopException(e);
          continue;
        }
        cancelledKeys = 0;
        needsToSelectAgain = false;
        final int ioRatio = this.ioRatio;
        if (ioRatio == 100) {
          try {
            processSelectedKeys();
          } finally {
            // Ensure we always run tasks.
            runAllTasks();
          }
        } else {
          final long ioStartTime = System.nanoTime();
          try {
            //2.处理产生网络IO事件的channel
            processSelectedKeys();
          } finally {
            // Ensure we always run tasks.
            final long ioTime = System.nanoTime() - ioStartTime;
            //3.处理任务队列
            runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
          }
        }
      } catch (Throwable t) {
        handleLoopException(t);
      }
      // Always handle shutdown even if the loop processing threw an exception.
      try {
        if (isShuttingDown()) {
          closeAll();
          if (confirmShutdown()) {
            return;
          }
        }
      } catch (Throwable t) {
        handleLoopException(t);
      }
    }
  }
}

上面的hasTasks()是若taskQueuetailTasks任务队列中有任务返回true没有则返回falseselectStrategy.calculateStrategy(selectNowSupplier, hasTasks())方法是有任务就返回selectNow的返回值 没任务返回-1,由于这儿已经添加了一个register0()的任务,所以这儿的返回值不是下面的任何一种策略,然后直接进入default,这个switch就直接结束。然后下面的判断ioRatio是否等于100,由于第一次的初始化为50,所以这个if判断是不会进入,会直接进入else,这个时候会先执行processSelectedKeys();方法。点进去看了一下,发现是处理产生的网络IO事件的channel,我们这儿先略过,我们今天的重点不是它,这个会在后续的博客中讲到。我们直接看runAllTasks(ioTime * (100 - ioRatio) / ioRatio);方法,我们跟进去查看相应的代码,具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  /**
  * 轮询任务队列中的所有任务,并通过{@link Runnable#run()}方法运行它们。此方法停止运行
  * 任务队列中的任务,如果运行时间超过{@code timeoutNanos},则返回。
  */
  protected boolean runAllTasks(long timeoutNanos) {
    //从scheduledTaskQueue转移定时任务到taskQueue
    fetchFromScheduledTaskQueue();
    Runnable task = pollTask();
    if (task == null) {
      //尝试在获取一次  如果有就执行
      afterRunningAllTasks();
      return false;
    }
    //计算本次任务循环的截止时间
    final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
    long runTasks = 0;
    long lastExecutionTime;
    //循环执行任务   到了指定时间  或者 没有任务执行了就会直接结束
    for (;;) {
      afeExecute(task);
      runTasks ++;
      //每64个任务检查一次超时,因为nanoTime()比较耗时
      if ((runTasks & 0x3F) == 0) {
        lastExecutionTime = ScheduledFutureTask.nanoTime();
        if (lastExecutionTime >= deadline) {
          break;
        }
      }
      task = pollTask();
      if (task == null) {
        lastExecutionTime = ScheduledFutureTask.nanoTime();
        break;
      }
    }
    afterRunningAllTasks();
    this.lastExecutionTime = lastExecutionTime;
    return true;
  }
}

上面的死循环就是执行任务队列taskQueue中的任务,两种情况会结束这个循环,第一种就是到了指定的时间,第二种就是没有任务执行了,就会结束这个死循环,但是这儿是有任务的。这儿的任务是register0(),我们找到对应的方法,继续跟进去,查看相应的代码,具体的代码如下:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected abstract class AbstractUnsafe implements Unsafe {
  	private void register0(ChannelPromise promise) {
      try {
        // 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
        // 调用在eventLoop之外
        //promise=DefaultChannelPromise
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
          return;
        }
        boolean firstRegistration = neverRegistered;
        //调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法  选择器看不同操作系统
        doRegister();
        neverRegistered = false;
        registered = true;
        // 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
        // 用户可能已经通过ChannelFutureListener中的管道触发事件。
        // 会执行handlerAdded方法
        pipeline.invokeHandlerAddedIfNeeded();
        safeSetSuccess(promise);
        //会执行channelRegistered
        pipeline.fireChannelRegistered();
        // 只有当通道从未被注册时,才激活该通道。这可以防止解雇
        // 如果取消注册并重新注册通道,则多个通道将激活。
        if (isActive()) {
          if (firstRegistration) {
            pipeline.fireChannelActive();
          } else if (config().isAutoRead()) {
            // 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
            // 这样我们就可以处理入站数据。
            //
            // See https://github.com/netty/netty/issues/4805
            beginRead();
          }
        }
      } catch (Throwable t) {
        // 直接关闭通道,避免FD泄漏。
        closeForcibly();
        loseFuture.setClosed();
        safeSetFailure(promise, t);
      }
    }
  }
}

上面的代码走来会调用doRegister();方法,大概的意思就是调用java原生channelregister的方法,并且将子类包装好的selector传入了进去,具体的代码如下:

public abstract class AbstractNioChannel extends AbstractChannel {
	//注册核心方法
  @Override
  protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
      try {
        //javaChannel() ==> ServerSocketChannel 通过反射创建出来nio底层channel
        //调用Nio底层将ServerSocketChannel注册到selector上
        selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
        return;
      } catch (CancelledKeyException e) {
        if (!selected) {
          //强制选择器现在选择,因为“已取消”的SelectionKey可能仍然是
          //缓存并没有删除,因为还没有调用Select.select(..)操作。
          eventLoop().selectNow();
          selected = true;
        } else {
          //我们之前在选择器上强制执行了select操作,但是SelectionKey仍然缓存
          //不管什么原因。JDK错误?
          throw e;
        }
      }
    }
  }
}

上面的doRegister()方法执行完,然后返回到原来的调用的地方,为了防止代码忘记,我们这儿再次贴出相应的代码,具体的代码如下:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected abstract class AbstractUnsafe implements Unsafe {
  	private void register0(ChannelPromise promise) {
      try {
        // 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
        // 调用在eventLoop之外
        //promise=DefaultChannelPromise
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
          return;
        }
        boolean firstRegistration = neverRegistered;
        //调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法  选择器看不同操作系统
        doRegister();
        neverRegistered = false;
        registered = true;
        // 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
        // 用户可能已经通过ChannelFutureListener中的管道触发事件。
        // 会执行handlerAdded方法
        pipeline.invokeHandlerAddedIfNeeded();
        safeSetSuccess(promise);
        //会执行channelRegistered
        pipeline.fireChannelRegistered();
        // 只有当通道从未被注册时,才激活该通道。这可以防止解雇
        // 如果取消注册并重新注册通道,则多个通道将激活。
        if (isActive()) {
          if (firstRegistration) {
            pipeline.fireChannelActive();
          } else if (config().isAutoRead()) {
            // 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
            // 这样我们就可以处理入站数据。
            //
            // See https://github.com/netty/netty/issues/4805
            beginRead();
          }
        }
      } catch (Throwable t) {
        // 直接关闭通道,避免FD泄漏。
        closeForcibly();
        loseFuture.setClosed();
        safeSetFailure(promise, t);
      }
    }
  }
}
  • 然后就会执行pipeline.invokeHandlerAddedIfNeeded();方法,我们继续跟进相应的代码,具体的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
	final void invokeHandlerAddedIfNeeded() {
    assert channel.eventLoop().inEventLoop();
    if (firstRegistration) {
      firstRegistration = false;
      // 我们现在注册到EventLoop。是时候调用通道处理程序的回调了,
      // 这些都是在注册之前添加的。
      callHandlerAddedForAllHandlers();
    }
  }
}

firstRegistration默认值是true,所以这个if判断会直接进,然后将firstRegistration值改成false,最后再去执行callHandlerAddedForAllHandlers();,我们继续跟进该方法,具体的代码如下:

public class DefaultChannelPipeline implements ChannelPipeline {
  private void callHandlerAddedForAllHandlers() {
    final PendingHandlerCallback pendingHandlerCallbackHead;
    synchronized (this) {
      assert !registered;
      // 该通道本身已注册。
      registered = true;
      pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
      this.pendingHandlerCallbackHead = null;
    }
    //这必须发生在synchronized(…)块之外,否则handlerAdded(…)可能在while中被调用
    //如果handleradd(…)试图从外部添加另一个处理程序,则会持有锁,从而产生死锁
    // EventLoop。
    PendingHandlerCallback task = pendingHandlerCallbackHead;
    while (task != null) {
      task.execute();
      task = task.next;
    }
  }
}

这儿的pendingHandlerCallbackHead属性在之前执行addLast()添加了一个new PendingHandlerAddedTask(ctx)而这儿目前只有一个task的任务,我们循环这个task,然后执行task.execute();方法,这儿执行的是PendingHandlerAddedTask(ctx)类中的execute()方法,我们继续跟进去,对应的代码如下:

public class DefaultChannelPipeline implements ChannelPipeline {
	private final class PendingHandlerAddedTask extends PendingHandlerCallback {
  	@Override
    void execute() {
      //ctx.executor();  当ctx中的executor为空的时候  获取NioEventLoop
      EventExecutor executor = ctx.executor();
      if (executor.inEventLoop()) {
        callHandlerAdded0(ctx);
      } else {
        try {
          executor.execute(this);
        } catch (RejectedExecutionException e) {
          if (logger.isWarnEnabled()) {
            logger.warn(
              "Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
              executor, ctx.name(), e);
          }
          remove0(ctx);
          ctx.setRemoved();
        }
      }
    }
  }
}

这个时候之前已经保存了thread的信息,所以这儿判断如果不是原来的线程执行的话,这个判断就不会成立。如果不是又会将当前的任务添加到taskQueue中去,这儿的判断是会成立的,我们会调用callHandlerAdded0(ctx);方法,我们继续跟进相应的代码,具体的代码如下:

public class DefaultChannelPipeline implements ChannelPipeline {
  private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
      ctx.callHandlerAdded();
    } catch (Throwable t) {
      boolean removed = false;
      try {
        remove0(ctx);
        ctx.callHandlerRemoved();
        removed = true;
      } catch (Throwable t2) {
        if (logger.isWarnEnabled()) {
          logger.warn("Failed to remove a handler: " + ctx.name(), t2);
        }
      }
      if (removed) {
        fireExceptionCaught(new ChannelPipelineException(
          ctx.handler().getClass().getName() +
          ".handlerAdded() has thrown an exception; removed.", t));
      } else {
        fireExceptionCaught(new ChannelPipelineException(
          ctx.handler().getClass().getName() +
          ".handlerAdded() has thrown an exception; also failed to remove.", t));
      }
    }
  }
}
  • 这个时候会直接调用ctx.callHandlerAdded();方法,我们继续跟进相应的代码。
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {
  final void callHandlerAdded() throws Exception {
    // We must call setAddComplete before calling handlerAdded. Otherwise if the handlerAdded method generates
    // any pipeline events ctx.handler() will miss them because the state will not allow it.
    //判断handlerState等于1  并且设置handlerState为2
    if (setAddComplete()) {
      handler().handlerAdded(this);
    }
  }
}

这个时候setAddComplete()方法通过死循环的方式和CAS操作将handlerState改成了ADD_COMPLETE表示添加完成,这个时候会继续执行handler().handlerAdded(this);这个handler()方法获取是在ServerBootstrap中添加那个匿名内部类,也就是ChannelInitializer,这个时候调用的是ChannelInitializer中的handlerAdded(this);方法,我们继续跟进去看看,具体的代码如下:

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
  @Override
  public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    if (ctx.channel().isRegistered()) {
      //对于当前的DefaultChannelPipeline实现,这应该总是正确的。
      //在handlerAdded(…)中调用initChannel(…)的好处是没有订单
      //如果一个通道初始化器将添加另一个通道初始化器,会让人感到惊讶。这是所有的处理程序
      //将按预期顺序添加。
      if (initChannel(ctx)) {
        // We are done with init the Channel, removing the initializer now.
        removeState(ctx);
      }
    }
  }
}

走来会先判断这个通道有没有注册,很明显这儿已经注册好了,然后这儿会执行initChannel(ctx)方法,我们打开对应的代码,具体的代码如下:

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
  private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
    if (initMap.add(ctx)) { // Guard against re-entrance.
      try {
        //我们写的ChannelInitializer.initChannel的方法 将在这里被调用
        initChannel((C) ctx.channel());
      } catch (Throwable cause) {
        // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
        // We do so to prevent multiple calls to initChannel(...).
        exceptionCaught(ctx, cause);
      } finally {
        //删除此节点
        ChannelPipeline pipeline = ctx.pipeline();
        if (pipeline.context(this) != null) {
          pipeline.remove(this);
        }
      }
      return true;
    }
    return false;
  }
}
  • 这个时候会调用initChannel((C) ctx.channel());方法,由于我们这儿添加的NettyTestHendler类没有实现ChannelInitializer这个类,所以调用的是下面这个方法,就是调用到ServerBootstrap类中的添加的匿名内部类中的方法,你会发现在调用这个方法后,finally中有个删除当前节点的操作,所以说ChannelInitializer这个节点是个特殊的节点,因为它只用来添加你自定义的pipeline,添加完成后,这个对应ChannelInitializer就会移除,具体的代码如下:
p.addLast(new ChannelInitializer<Channel>() {
  @Override
  public void initChannel(final Channel ch) throws Exception {
    //System.out.println(ch==channel);   true
    final ChannelPipeline pipeline = ch.pipeline();
    //System.out.println(pipeline==p);  true
    //config.handler()=自己创建的new ChannelInitializer<ServerSocketChannel>()
    ChannelHandler handler = config.handler();
    if (handler != null) {
      pipeline.addLast(handler);
    }
    ch.eventLoop().execute(new Runnable() {
      @Override
      public void run() {
        //System.out.println("执行了");
        //bossGroup将客户端连接转交给workerGroup
        pipeline.addLast(new ServerBootstrapAcceptor(
          ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
      }
    });
  }
});

上面的方法会取出我们手动添加的pipeline,这个时候我们通过对应的方法addLast(handler);,将它添加到pipeline中去,这儿有一点和之前的调用不一样,我们继续分析,具体的代码如下:

public class DefaultChannelPipeline implements ChannelPipeline {
	@Override
  public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
    //group=null
    //name =null
    //handler=new ChannelInitializer<Channel>
    final AbstractChannelHandlerContext newCtx;
    synchronized (this) {
      //检查添加
      checkMultiplicity(handler);
      //filterName(name, handler)   当我们没有指定名字时  给我们默认生成一个
      //new DefaultChannelHandlerContext()
      newCtx = newContext(group, filterName(name, handler), handler);
      addLast0(newCtx);
      // If the registered is false it means that the channel was not registered on an eventLoop yet.
      // In this case we add the context to the pipeline and add a task that will call
      // ChannelHandler.handlerAdded(...) once the channel is registered.
      if (!registered) {
        //判断handlerState属性等于0  并且设置为1 置为待处理状态
        newCtx.setAddPending();
        callHandlerCallbackLater(newCtx, true);
        return this;
      }
      //返回NioEvenGroup
      EventExecutor executor = newCtx.executor();
      if (!executor.inEventLoop()) {
        callHandlerAddedInEventLoop(newCtx, executor);
        return this;
      }
    }
    callHandlerAdded0(newCtx);
    return this;
  }
}

上面的第一个if判断是不会进的,因为registered已经在前面的一个方法将其改成true了,这个时候第二个判断,由于当前的thread存的是NioEventLoop,但是这儿是否,所以下面那个判断也不会进的。最后就会执行callHandlerAdded0(newCtx);方法,我们会发现调用的链路是一样的,最终会执行到我自己写的handlerAdded方法中去。如果对应的handlerAdded没有写,就会调用父类的ChannelInitializer中的handlerAdded这个时候又会重新调用一下你继承ChannelInitializer的子类中的initChannel方法。至此pipeline.addLast(handler);执行完成,我们继续回到原来的代码,继续跟进下去。具体的代码如下:

p.addLast(new ChannelInitializer<Channel>() {
  @Override
  public void initChannel(final Channel ch) throws Exception {
    //System.out.println(ch==channel);   true
    final ChannelPipeline pipeline = ch.pipeline();
    //System.out.println(pipeline==p);  true
    //config.handler()=自己创建的new ChannelInitializer<ServerSocketChannel>()
    ChannelHandler handler = config.handler();
    if (handler != null) {
      pipeline.addLast(handler);
    }
    ch.eventLoop().execute(new Runnable() {
      @Override
      public void run() {
        //System.out.println("执行了");
        //bossGroup将客户端连接转交给workerGroup
        pipeline.addLast(new ServerBootstrapAcceptor(
          ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
      }
    });
  }
});

这个时候会执行ch.eventLoop().execute()方法,这个方法又是将当前的任务添加到任务队列,对应的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
	@Override
  public void execute(Runnable task) {
    if (task == null) {
      throw new NullPointerException("task");
    }
    //调用doStartThread方法启动事件轮询后此方法返回true
    boolean inEventLoop = inEventLoop();
    //将任务加入线程队列
    addTask(task);
    //判断当前执行此任务的线程是否是SingleThreadEventExecutor
    if (!inEventLoop) {
      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)) {
      //唤醒阻塞的selector
      wakeup(inEventLoop);
    }
  }
}

由于刚才已经启动线程了,也将线程的信息存到thread中去了,所以这儿调用NinEventLoop();方法就会返回的是true,所以下面的if判断就会为false这样就不会启动线程了,而是将这个任务添加到taskQueue这个任务队列中去,等待下一次轮训的时候调用到它,我们继续查看register0()方法,让我们继续重现原来的代码,具体的代码如下:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected abstract class AbstractUnsafe implements Unsafe {
  	private void register0(ChannelPromise promise) {
      try {
        // 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
        // 调用在eventLoop之外
        //promise=DefaultChannelPromise
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
          return;
        }
        boolean firstRegistration = neverRegistered;
        //调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法  选择器看不同操作系统
        doRegister();
        neverRegistered = false;
        registered = true;
        // 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
        // 用户可能已经通过ChannelFutureListener中的管道触发事件。
        // 会执行handlerAdded方法
        pipeline.invokeHandlerAddedIfNeeded();
        safeSetSuccess(promise);
        //会执行channelRegistered
        pipeline.fireChannelRegistered();
        // 只有当通道从未被注册时,才激活该通道。这可以防止解雇
        // 如果取消注册并重新注册通道,则多个通道将激活。
        if (isActive()) {
          if (firstRegistration) {
            pipeline.fireChannelActive();
          } else if (config().isAutoRead()) {
            // 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
            // 这样我们就可以处理入站数据。
            //
            // See https://github.com/netty/netty/issues/4805
            beginRead();
          }
        }
      } catch (Throwable t) {
        // 直接关闭通道,避免FD泄漏。
        closeForcibly();
        loseFuture.setClosed();
        safeSetFailure(promise, t);
      }
    }
  }
}

这个时候pipeline.invokeHandlerAddedIfNeeded();已经执行完成,要执行下面的safeSetSuccess(promise);方法了,我们继续跟进相应的代码,具体的代码如下:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected final void safeSetSuccess(ChannelPromise promise) {
    if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
      logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
    }
  }
}

上面的代码由于传进来的promiseDefaultChannelPromise,而VoidChannelPromise没有子类,所以这个前面的判断就为true,这个时候就会执行promise.trySuccess()方法,我们继续跟进去看看,具体的代码如下:

public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
	@Override
  public boolean trySuccess() {
    return trySuccess(null);
  }
}

上面的代码继续调用trySuccess(null);,我们继续跟进去看看对应的代码,具体的代码如下:

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
	@Override
  public boolean trySuccess(V result) {
    return setSuccess0(result);
  }
  
  private boolean setSuccess0(V result) {
    return setValue0(result == null ? SUCCESS : result);
  }
  
  private boolean setValue0(Object objResult) {
    //记住这儿的CAS设置值,这儿设置完就表示注册完成了,后面调用dobind0方法会用到
    if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
        RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
      //由于前面添加了一个监听器,所以这儿的判断是不会为false的
      if (checkNotifyWaiters()) {
        notifyListeners();
      }
      return true;
    }
    return false;
  }
  
  private void notifyListeners() {
    //这儿获取的NioEventLoop
    EventExecutor executor = executor();
    //这个判断是成立的,还是当前线程执行这个任务
    if (executor.inEventLoop()) {
      final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
      //获取futureListener的栈的深度,这儿获取的是0
      final int stackDepth = threadLocals.futureListenerStackDepth();
      //当栈的深度小于8的时候
      if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
        //将futureListener的栈的深度加上1
        threadLocals.setFutureListenerStackDepth(stackDepth + 1);
        try {
          //调用如下的方法
          notifyListenersNow();
        } finally {
          threadLocals.setFutureListenerStackDepth(stackDepth);
        }
        return;
      }
    }
    safeExecute(executor, new Runnable() {
      @Override
      public void run() {
        notifyListenersNow();
      }
    });
  }
  
   private void notifyListenersNow() {
     Object listeners;
     synchronized (this) {
       // 仅在有要通知的侦听器且我们尚未通知侦听器时继续进行
       // 下面两个值notifyingListeners初始为false
       // 这儿这个listeners不为空,我们在之前添加了一个监听器
       if (notifyingListeners || this.listeners == null) {
         return;
       }
       notifyingListeners = true;
       listeners = this.listeners;
       this.listeners = null;
     }
     //由于前面添加ChannelFutureListener类,所以下面的判断是会执行else中代码
     for (;;) {
       if (listeners instanceof DefaultFutureListeners) {
         notifyListeners0((DefaultFutureListeners) listeners);
       } else {
         notifyListener0(this, (GenericFutureListener<?>) listeners);
       }
       synchronized (this) {
         if (this.listeners == null) {
           // Nothing can throw from within this method, so setting notifyingListeners back to false does not
           // need to be in a finally block.
           notifyingListeners = false;
           return;
         }
         listeners = this.listeners;
         this.listeners = null;
       }
     }
   }
  
  //执行下面的的方法
  private static void notifyListener0(Future future, GenericFutureListener l) {
    try {
      //这个时候会调用到我们原来在AbstractBootstrap的dobind方法中添加的监听器
      l.operationComplete(future);
    } catch (Throwable t) {
      if (logger.isWarnEnabled()) {
        logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
      }
    }
  }
}

上面代码最终会调用我在AbstractBootstrapdobind方法中添加的监听器,这个时候调用的代码就如下所示:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  private ChannelFuture doBind(final SocketAddress localAddress) {
    //初始化和注册
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
      return regFuture;
    }
    if (regFuture.isDone()) {
      // At this point we know that the registration was complete and successful.
      ChannelPromise promise = channel.newPromise();
      doBind0(regFuture, channel, localAddress, promise);
      return promise;
    } else {
      final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
      regFuture.addListener(new ChannelFutureListener() {
        //会执行如下的代码
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
          Throwable cause = future.cause();
          if (cause != null) {
            // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
            // IllegalStateException once we try to access the EventLoop of the Channel.
            promise.setFailure(cause);
          } else {
            // Registration was successful, so set the correct executor to use.
            // See https://github.com/netty/netty/issues/2586
            // 设置注册成功
            promise.registered();
            doBind0(regFuture, channel, localAddress, promise);
          }
        }
      });
      return promise;
    }
  }
}

上面的监听器会调用operationComplete(ChannelFuture future)方法,由于前面没有异常,所以这儿会调用doBind0(regFuture, channel, localAddress, promise);方法,我们继续跟进去查看对应的代码,具体的代码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
	private static void doBind0(
    final ChannelFuture regFuture, final Channel channel,
    final SocketAddress localAddress, final ChannelPromise promise) {
    // 在触发channelregister()之前调用此方法。给用户处理程序设置的机会
    // 管道在其channelRegistered()实现中。
    //这些任务最终被事件轮询线程同步调用
    channel.eventLoop().execute(new Runnable() {
      @Override
      public void run() {
        System.out.println(" channel.eventLoop().execute(new Runnable() ");
        if (regFuture.isSuccess()) {
          channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
        } else {
          promise.setFailure(regFuture.cause());
        }
      }
    });
  }
}

你会发现上面的代码一样是往taskQueue中添加了一个任务,等待对应的线程调用。到这里register0()方法中的safeSetSuccess(promise);就执行完成了。要记住这儿taskQueue中有两个任务,一个是添加ServerBootstrapAcceptor类到pipeline,还有一个就是执行dobind0()方法。我们再次回到执行原来的代码的地方,具体的代码如下:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
	protected abstract class AbstractUnsafe implements Unsafe {
  	private void register0(ChannelPromise promise) {
      try {
        // 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
        // 调用在eventLoop之外
        //promise=DefaultChannelPromise
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
          return;
        }
        boolean firstRegistration = neverRegistered;
        //调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法  选择器看不同操作系统
        doRegister();
        neverRegistered = false;
        registered = true;
        // 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
        // 用户可能已经通过ChannelFutureListener中的管道触发事件。
        // 会执行handlerAdded方法
        pipeline.invokeHandlerAddedIfNeeded();
        safeSetSuccess(promise);
        //会执行channelRegistered
        pipeline.fireChannelRegistered();
        // 只有当通道从未被注册时,才激活该通道。这可以防止解雇
        // 如果取消注册并重新注册通道,则多个通道将激活。
        if (isActive()) {
          if (firstRegistration) {
            pipeline.fireChannelActive();
          } else if (config().isAutoRead()) {
            // 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
            // 这样我们就可以处理入站数据。
            //
            // See https://github.com/netty/netty/issues/4805
            beginRead();
          }
        }
      } catch (Throwable t) {
        // 直接关闭通道,避免FD泄漏。
        closeForcibly();
        loseFuture.setClosed();
        safeSetFailure(promise, t);
      }
    }
  }
}

这个时候会调用对应的pipelinefireChannelRegistered();方法,到此通道已经激活。所以下面的两个判断都不会进。这个这个任务就执行完成。所以下面会执行pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));pipeline中又添加了一个pipeline,这个是pipeline如下图所示:

在这里插入图片描述

下篇博客我会主要介绍另一个任务dobind0()方法,同样也是一个核心的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值