Netty源码(四)之ServerBootstrap的bind(二)的过程

在上篇博客:Netty源码(三)之ServerBootstrap的bind(一)的过程,我们讲了NioServerSocketChannel初始化和创建的过程,我们这篇博客接着上篇博客继续讲,我们继续重现上一篇博客的代码,具体的代码如下:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

//服务端
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //就是一个死循环,不停地检测IO事件,处理IO事件,执行任务
        //创建一个线程组:接受客户端连接   主线程
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//cpu核心数*2
        //创建一个线程组:接受网络操作   工作线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();  //cpu核心数*2
        //是服务端的一个启动辅助类,通过给他设置一系列参数来绑定端口启动服务
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 我们需要两种类型的人干活,一个是老板,一个是工人,老板负责从外面接活,
        // 接到的活分配给工人干,放到这里,bossGroup的作用就是不断地accept到新的连接,将新的连接丢给workerGroup来处理
        serverBootstrap.group(bossGroup, workerGroup)
                //设置使用NioServerSocketChannel作为服务器通道的实现
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
                .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
                //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
                // 是netty的一大核心概念,表示数据流经过的处理器
                .handler(new NettyTestHendler())
                //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
                    }
                });
        System.out.println(".........server  init..........");
        // 这里就是真正的启动过程了,绑定9090端口,等待服务器启动完毕,才会进入下行代码
        ChannelFuture future = serverBootstrap.bind(9090).sync();
        System.out.println(".........server start..........");
        //等待服务端关闭socket
        future.channel().closeFuture().sync();
        // 关闭两组死循环
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

上面的代码是服务端初始化的总的代码,我们继续跟进我们上篇博客所看的的代码的地方,具体的代码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
	//初始化并注册
    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            //通过反射创建NioServerSocketChannel
            //channelFactory=new ReflectiveChannelFactory  ---> constructor=NioServerSocketChannel.class.getConstructor();
            //channel=NioServerSocketChannel
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        //config().group()==bossGroup  ===> EventLoopGroup bossGroup=new NioEventLoopGroup(1);
        //register开启了事件轮询线程
        //config().group()  boosGroup
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
        return regFuture;
    }
}

上篇博客我们执行完了init(channel);,这篇博客我们分析后续的流程,走来执行的config().group().register(channel);方法,这儿config().group()返回的是bossGroup,是我们之前创建,这个对象中有哪些内容,可以看看我的Netty源码的解析的第一篇,这个时候执行register(channel)对应的方法,具体的代码如下:

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
	@Override
    public ChannelFuture register(Channel channel) {
        //channel=NioServerSocketChannel
        return register(new DefaultChannelPromise(channel, this));
    }
}

上面的代码先创建好DefaultChannelPromise(channel, this)对象,我们继续跟进去查看对应对象的代码,具体的代码如下:

public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
	public DefaultChannelPromise(Channel channel, EventExecutor executor) {
        //channel=NioServerSocketChannel
        //executor=NioEventLoop
    		//调用父类的构造函数
        super(executor);
        this.channel = checkNotNull(channel, "channel");
    }
}
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
	public DefaultPromise(EventExecutor executor) {
        //NioEventLoop.this
        this.executor = checkNotNull(executor, "executor");
    }
}

上面的代码就是进行对应的赋值,具体的DefaultChannelPromise对象图如下图所示:

在这里插入图片描述

最终我们创建的对象如上图所示,这个时候回到我们的register(new DefaultChannelPromise(channel, this));方法,我们继续回到原来的代码,继续跟进下去,具体的代码如下:

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
	@Override
  public ChannelFuture register(Channel channel) {
      //channel=NioServerSocketChannel
      return register(new DefaultChannelPromise(channel, this));
  }
  @Override
  public ChannelFuture register(final ChannelPromise promise) {
      ObjectUtil.checkNotNull(promise, "promise");
      //promise=DefaultChannelPromise
      //promise.channel()=NioServerSocketChannel
      //Unsafe=AbstractChannel.unsafe=promise.channel().unsafe();
      promise.channel().unsafe().register(this, promise);
      return promise;
  }
}

上面的register(this, promise);方法调用的是AbstractUnsafe中的register方法,具体的代码如下:

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
    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);
      }
    }
  }
}

上面的this指向调用者对象,所以这儿的thisbossGroup,而this.eventLoop=NioEventLoop==>SingleThreadEventLoop.this,对应的就是SingleThreadEventLoop.this,这个时候会调用eventLoop.inEventLoop()方法,我们跟进去看看对应的代码是什么?具体的代码如下:

public abstract class AbstractEventExecutor extends AbstractExecutorService implements EventExecutor {
	@Override
  public boolean inEventLoop() {
    return inEventLoop(Thread.currentThread());
  }
}
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
	@Override
  public boolean inEventLoop(Thread thread) {
    return thread == this.thread;
  }
}

原来是判断当前的线程和执行的线程是不是同一个线程,仔细看上面的代码,你会发现不管是if还是else都是会执行register0(promise);但是在这儿thread没有赋值,所以是等于false,所以会先执行execute方法,具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  //专门执行register0()方法
  @Override
  public void execute(Runnable task) {
    System.out.println("ccccccccccc");
    if (task == null) {
      throw new NullPointerException("task");
    }
    //调用doStartThread方法启动事件轮询后此方法返回true
    //这儿第一次进入的thread的属性没有初始化,所以inEventLoop的值为false
    boolean inEventLoop = inEventLoop();
    //将任务加入线程队列
    addTask(task);
    //判断当前执行此任务的线程是否是SingleThreadEventExecutor
    if (!inEventLoop) {
      startThread();
      if (isShutdown()) {
        boolean reject = false;
        try {
          f (removeTask(task)) {
            reject = true;
          }
        } catch (UnsupportedOperationException e) {
        }
        if (reject) {
          reject();
        }
      }
    }
    if (!addTaskWakesUp && wakesUpForTask(task)) {
      //唤醒阻塞的selectT
      wakeup(inEventLoop);
    }
  }
}

上面的代码先执行的是addTask(task),我们继续跟进相应的代码,具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  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);
  }
}

记住我们这儿是将任务添加到taskQueue队列中去,这儿的taskQueue是我们之前创建NioEventLoopGroup对象的时候创建,并且它的长度为最大的int的长度。这儿任务是会添加成功,我们继续返回到原来我们执行的代码地方,继续跟进剩下的代码,具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  @Override
  public void execute(Runnable task) {
    System.out.println("ccccccccccc");
    if (task == null) {
      throw new NullPointerException("task");
    }
    //调用doStartThread方法启动事件轮询后此方法返回true
    //这儿第一次进入的thread的属性没有初始化,所以inEventLoop的值为false
    boolean inEventLoop = inEventLoop();
    //将任务加入线程队列
    addTask(task);
    //判断当前执行此任务的线程是否是SingleThreadEventExecutor
    //下面这个判断是成立的,我们会执行startThread();
    if (!inEventLoop) {
      startThread();
      if (isShutdown()) {
        boolean reject = false;
        try {
          f (removeTask(task)) {
            reject = true;
          }
        } catch (UnsupportedOperationException e) {
        }
        if (reject) {
          reject();
        }
      }
    }
    if (!addTaskWakesUp && wakesUpForTask(task)) {
      //唤醒阻塞的selectT
      wakeup(inEventLoop);
    }
  }
}

上面的代码的if判断是成立,我们会执行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);
          }
        }
      }
    }
  }
}

上面的代码走来将state的状态从ST_NOT_STARTED通过CAS操作改成ST_STARTED,如果执行doStartThread();出现异常,就直接回滚,将state的状态从ST_STARTED通过CAS操作改成ST_NOT_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 {
          //执行对应的run方法。
          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()方法,这儿会调用线程工厂中的execute()方法,对应的代码如下:

public final class ThreadPerTaskExecutor implements Executor {
	@Override
    public void execute(Runnable command) {
        //new DefaultThreadFactory()
        threadFactory.newThread(command).start();
    }
}

可以发现上面的代码就是启动一个线程,这个线程的就会在后台一直循环的执行,至于这个线程中具体的代码,我会在下一篇博客具体说到,这儿就不展开分析,这个时候doStartThread(),这个时候我们返回到调用的地方,继续查看后续的代码,具体的代码如下:

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);
          }
        }
      }
    }
  }
}

上面的代码执行完,将success设置为true(没有出错的前提下),如果出错了,通过CAS的操作,将线程的状态从ST_STARTED改成ST_NOT_STARTED,上面的代码执行完,返回对应的startThread()调用的地方,我们继续跟进代码,具体的代码如下:

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  @Override
  public void execute(Runnable task) {
    System.out.println("ccccccccccc");
    if (task == null) {
      throw new NullPointerException("task");
    }
    //调用doStartThread方法启动事件轮询后此方法返回true
    //这儿第一次进入的thread的属性没有初始化,所以inEventLoop的值为false
    boolean inEventLoop = inEventLoop();
    //将任务加入线程队列
    addTask(task);
    //判断当前执行此任务的线程是否是SingleThreadEventExecutor
    //下面这个判断是成立的,我们会执行startThread();
    if (!inEventLoop) {
      startThread();
      if (isShutdown()) {
        boolean reject = false;
        try {
          f (removeTask(task)) {
            reject = true;
          }
        } catch (UnsupportedOperationException e) {
        }
        if (reject) {
          reject();
        }
      }
    }
    if (!addTaskWakesUp && wakesUpForTask(task)) {
      //唤醒阻塞的selectT
      wakeup(inEventLoop);
    }
  }
}

这个时候后面的判断只有最后一个判断是正确的,所以我们会执行wakeup(inEventLoop);这个方法,我们就不继续跟进去了,因为这儿就是唤醒selector,同时将wakeUp通过CAS操作将值从false改成true至此AbstractBootstrap中的initAndRegister()执行完成,这个时候会返回到最终调用的地方,具体的代码如下:

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 {
      // Registration future is almost always fulfilled already, but just in case it's not.
      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;
    }
  }
}

上面的代码会先判断regFuture.isDone(),我们跟进去看看,具体的代码如下:

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
	private static final AtomicReferenceFieldUpdater<DefaultPromise, Object> RESULT_UPDATER =
            AtomicReferenceFieldUpdater.newUpdater(DefaultPromise.class, Object.class, "result");
  private static final Object UNCANCELLABLE = new Object();
  private volatile Object result;
  
  @Override
  public boolean isDone() {
    return isDone0(result);
  }
  
  private static boolean isDone0(Object result) {
        return result != null && result != UNCANCELLABLE;
    }
  
}

我们发现最终的就是判断result != null && result != UNCANCELLABLE;是否为真,前面的第一次赋值在promise.setUncancellable()方法中,后面一次赋值是在safeSetSuccess(promise)两个方法都在register0()方法中,准确的说,上面的判读是否成立,是与是否注册完成,如果已经完成了就返回true,如果没有完成就返回false,如果是返回true会执行下面doBind0()方法,具体的代码如下:

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中去。到此返回为true的情况已经分析完了,我们在来查看一下返回false的情况,具体的代码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  private ChannelFuture doBind(final SocketAddress localAddress) {
   //省略一部分代码
    } else {
      // Registration future is almost always fulfilled already, but just in case it's not.
      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;
    }
  }
}

上面的addListener(),我们继续跟进去,具体的代码如下:

public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
  @Override
  public ChannelPromise addListener(GenericFutureListener<? extends Future<? super Void>> listener) {
    //调用父类的方法
    super.addListener(listener);
    return this;
  }
}

我们发现最终是调用父类的方法,我们继续跟进去,具体的代码如下:

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
	@Override
  public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
    checkNotNull(listener, "listener");
    synchronized (this) {
      //继续跟进代码
      addListener0(listener);
    }
    if (isDone()) {
      notifyListeners();
    }
    return this;
  }
}

我们发现调用的addListener0(listener);方法,具体的代码如下:

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
  private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
    if (listeners == null) {
      listeners = listener;
    } else if (listeners instanceof DefaultFutureListeners) {
      ((DefaultFutureListeners) listeners).add(listener);
    } else {
      listeners = new DefaultFutureListeners((GenericFutureListener<?>) listeners, listener);
    }
  }
}

我们发现将刚才的listener添加到DefaultFutureListeners中去,这个时候,在后面再次判断有没有注册完成,如果注册完成,就会调用刚才那个添加的监听器中的operationComplete的方法(在保证没有出错的情况下),而这个方法是在register0()中的safeSetSuccess(promise);方法调用的。因为没有注册完成,就只有两种情况,一种是原来开启的线程没有执行完注册,而这个时候主线程已经执行到判断有没有注册完成,这个时候一定是没有注册完成的。这个时候等注册完成后就会调用operationComplete方法,因为safeSetSuccess(promise);方法执行完表示注册完成了。还有一种情况就是原来开启的线程没有执行完注册,而这个时候主线程已经执行到判断有没有注册完成,这个时候一定是没有注册完成的。调用safeSetSuccess(promise);成功后表示注册成功,但是这个调用出现了异常,就会执行operationComplete中的另一个if分支,表示调用失败,并返回对应的异常信息。

到此整个bind()方法就执行完成了,下篇博客我们要分析SingleThreadEventExecutor.this.run();这个核心的方法。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值