一起学Netty(十八)netty源码学习之netty server端源码初读(上)

来源:互联网 发布:万代告淘宝 编辑:程序博客网 时间:2024/05/22 02:07

server端是使用了Reactor模式对nio进行了一些封装,Reactor模式网上有很多资料,不赘述,了解了这个模式开始看源码

netty的版本是4.0.21.Final


[html] view plain copy
  1. <dependency>  
  2.     <groupId>io.netty</groupId>  
  3.     <artifactId>netty-all</artifactId>  
  4.     <version>4.0.21.Final</version>  
  5. </dependency>  



netty端server端的比较经典的代码如下:

(代码一)

[java] view plain copy
  1. public void start(){  
  2.         EventLoopGroup bossGroup = new NioEventLoopGroup(1);  
  3.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
  4.         try {  
  5.             ServerBootstrap sbs = new ServerBootstrap();  
  6.             sbs.group(bossGroup,workerGroup);  
  7.             sbs.channel(NioServerSocketChannel.class);  
  8.             sbs.localAddress(new InetSocketAddress(port));  
  9.             sbs.childHandler(new ChannelInitializer<SocketChannel>() {  
  10.                           
  11.                         protected void initChannel(SocketChannel ch) throws Exception {  
  12.                             ch.pipeline().addLast("decoder"new StringDecoder());  
  13.                             ch.pipeline().addLast("encoder"new StringEncoder());  
  14.                             ch.pipeline().addLast(new HelloWorldServerHandler());  
  15.                         };  
  16.                           
  17.                     }).option(ChannelOption.SO_BACKLOG, 128)     
  18.                     .childOption(ChannelOption.SO_KEEPALIVE, true);  
  19.              // 绑定端口,开始接收进来的连接  
  20.              ChannelFuture future = sbs.bind(port).sync();    
  21.                
  22.              System.out.println("Server start listen at " + port );  
  23.              future.channel().closeFuture().sync();  
  24.         } catch (Exception e) {  
  25.             bossGroup.shutdownGracefully();  
  26.             workerGroup.shutdownGracefully();  
  27.         }  
  28.     }  



step1:

这是一段普通不能再普通的代码了,先看EventLoopGroup这个类,这个类是EventLoop的一个集合,我们先简单的看下EventLoopGroup的一个具体实现NioEventLoopGroup


[html] view plain copy
  1. public NioEventLoopGroup() {  
  2.         this(0);  
  3. }  
  4.   
  5. public NioEventLoopGroup(int nThreads) {  
  6.         this(nThreads, null);  
  7. }  
  8.   
  9. public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {  
  10.         this(nThreads, threadFactory, SelectorProvider.provider());  
  11. }  
  12.   
  13. public NioEventLoopGroup(  
  14.             int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {  
  15.         super(nThreads, threadFactory, selectorProvider);  
  16. }  

NioEventLoopGroup构造函数最后调用了它父类MultithreadEventLoopGroup的构造函数:

(代码二)

[java] view plain copy
  1. protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
  2.         super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);  
  3. }  

其中DEFAULT_EVENT_LOOP_THREADS设置了这个group中的个数,如果我们没有默认传递参数,系统默认会是:

[java] view plain copy
  1. DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(  
  2.                 "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));  
一般是你CPU *2的个数,在Reactor模式中,mainReactor角色一般只需要一个线程就搞定了,subReactor角色就是那个苦逼的worker了,一般boss(mainReactor)一个就够了,subReactor就是需要多个了,所以在【代码一】中:

[java] view plain copy
  1. EventLoopGroup bossGroup = new NioEventLoopGroup(1);  
  2. EventLoopGroup workerGroup = new NioEventLoopGroup();  

看名字就知道哪个EventLoopGroup对应哪一个Reactor模型中的角色了


回到上面一个话题中,我们接着【代码二】看,它接着调用它的父类MultithreadEventExecutorGroup的构造函数

[java] view plain copy
  1. protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
  2.         if (nThreads <= 0) {  
  3.             throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));  
  4.         }  
  5.   
  6.         if (threadFactory == null) {  
  7.             threadFactory = newDefaultThreadFactory();  
  8.         }  
  9.   
  10.         children = new SingleThreadEventExecutor[nThreads];  
  11.         if (isPowerOfTwo(children.length)) {  
  12.             chooser = new PowerOfTwoEventExecutorChooser();  
  13.         } else {  
  14.             chooser = new GenericEventExecutorChooser();  
  15.         }  
  16.   
  17.         for (int i = 0; i < nThreads; i ++) {  
  18.             boolean success = false;  
  19.             try {  
  20.                 children[i] = newChild(threadFactory, args);  
  21.                 success = true;  
  22.             } catch (Exception e) {  
  23.                 // TODO: Think about if this is a good exception type  
  24.                 throw new IllegalStateException("failed to create a child event loop", e);  
  25.             } finally {  
  26.                 if (!success) {  
  27.                     for (int j = 0; j < i; j ++) {  
  28.                         children[j].shutdownGracefully();  
  29.                     }  
  30.   
  31.                     for (int j = 0; j < i; j ++) {  
  32.                         EventExecutor e = children[j];  
  33.                         try {  
  34.                             while (!e.isTerminated()) {  
  35.                                 e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);  
  36.                             }  
  37.                         } catch (InterruptedException interrupted) {  
  38.                             Thread.currentThread().interrupt();  
  39.                             break;  
  40.                         }  
  41.                     }  
  42.                 }  
  43.             }  
  44.         }  
这是本质的方法,所有的工作基本上都在这里做了,因为前面我们很懒惰,啥都没有做,因为我们构造NioEventLoopGroup的时候,没有传递任何参数,netty给了一些默认的实现,首先newDefaultThreadFactory用来穿件一个默认的ThreadFactory,然后初始化了一个叫做children的实例变量,该children的定义是这样的

[java] view plain copy
  1. private final EventExecutor[] children;  
EventExecutor是一个Executor,也就是一个线程执行器,换而言之,children = new SingleThreadEventExecutor[nThreads]这行代码对children进行了初始化动作,nThreads表示个数,如果我们CPU是4核的话,4*2表示初始化8个SingleThreadEventExecutor线程执行器,SingleThreadEventExecutor其实就是Reactor模型中真正工作的worker了,我们先简单的看下SingleThreadEventExecutor源码,下面列出2段SingleThreadEventExecutor的代码片段

SingleThreadEventExecutor片段一:

[java] view plain copy
  1. private final EventExecutorGroup parent;  
  2. private final Queue<Runnable> taskQueue;  
  3. final Queue<ScheduledFutureTask<?>> delayedTaskQueue = new PriorityQueue<ScheduledFutureTask<?>>();  
  4.   
  5. private final Thread thread;  
  6. private final Semaphore threadLock = new Semaphore(0);  
  7. private final Set<Runnable> shutdownHooks = new LinkedHashSet<Runnable>();  
  8. private final boolean addTaskWakesUp;  
首先先看taskQueue这是一个Runnable的任务队列,还有一个delayedTaskQueue延迟队列,最后每一个SingleThreadEventExecutor都绑定了唯一的Thread,用这个thread去执行这些taskQueue和delayedTaskQueue中的任务

SingleThreadEventExecutor片段二:

[java] view plain copy
  1. thread = threadFactory.newThread(new Runnable() {  
  2.             @Override  
  3.             public void run() {  
  4.                 boolean success = false;  
  5.                 updateLastExecutionTime();  
  6.                 try {  
  7.                     SingleThreadEventExecutor.this.run();  
  8.                     success = true;  
  9.                 } catch (Throwable t) {  
  10.                     logger.warn("Unexpected exception from an event executor: ", t);  
  11.                 }   
这个thread最后回去调用SingleThreadEventExecutor的run方法,这个后面再一起分析


回到上文children的初始化的代码中来,初始化好之后,开始为一个child赋值:

[java] view plain copy
  1. children[i] = newChild(threadFactory, args);  
看newChild方法:

[java] view plain copy
  1. @Override  
  2.     protected EventExecutor newChild(  
  3.             ThreadFactory threadFactory, Object... args) throws Exception {  
  4.         return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);  
  5. }  
  6.   
  7. NioEventLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {  
  8.         super(parent, threadFactory, false);  
  9.         if (selectorProvider == null) {  
  10.             throw new NullPointerException("selectorProvider");  
  11.         }  
  12.         provider = selectorProvider;  
  13.         selector = openSelector();  
  14. }  
  15.   
  16. protected SingleThreadEventLoop(EventLoopGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {  
  17.         super(parent, threadFactory, addTaskWakesUp);  
  18.  }  
可以看出最后还是调用的SingleThreadEventExecutor的构造函数,期间做了selector的处理,我们知道NIO是基于事件驱动的,所以netty也是离不开selector,所以每一个NioEventLoop(上文描述的SingleThreadEventLoop的子类)都需要绑定一个selector,这样在netty初始化channel的时候,只需要将channel绑定selector就可以了,关于openSelector这个方法,netty也进行了大量的优化,关于openselector这个方法,大家可以参考http://budairenqin.iteye.com/blog/2215896,我这个就不重复介绍了


好了,到此为止NioEventLoopGroup的源码就已经分析完了,此时NioEventLoopGroup中的每一个NioEventLoop中绑定的thread还没有start,我们接着看


step2:

回到代码一:

[java] view plain copy
  1. ServerBootstrap sbs = new ServerBootstrap();  
  2. sbs.group(bossGroup,workerGroup);  
group方法是将我们刚刚初始化好的bossGroup,workerGroup分别进行赋值(当然需要进行赋值绑定啦,否则实例化他们干啥用,实例化就是为了用,多说两句,不忘初心,bossGroup和workerGroup这两个的使命是什么,重述一遍,bossGroup和workerGroup中维护的都是维护了两个队列,一个thread,boss的thread线程是用来接收链接的然后转发给worker处理,worker列队就是一个个任务,等待worker的thread做处理,但是这两个group中的thread都没有start呢,并且selector都没有注册,哈哈,不忘初心,做人也是一样)


废话不多说,workerGroup赋值给ServerBootstrap实例的childGroup,bossGroup赋值给AbstractBootstrap的group,具体代码如下:

ServerBootstrap.java

[java] view plain copy
  1. private volatile EventLoopGroup childGroup;  
  2.   
  3. public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {  
  4.         super.group(parentGroup);  
  5.         if (childGroup == null) {  
  6.             throw new NullPointerException("childGroup");  
  7.         }  
  8.         if (this.childGroup != null) {  
  9.             throw new IllegalStateException("childGroup set already");  
  10.         }  
  11.         this.childGroup = childGroup;  
  12.         return this;  
  13. }  
AbstractBootstrap.java

[java] view plain copy
  1. private volatile EventLoopGroup group;  
  2.   
  3. AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) {  
  4.         group = bootstrap.group;  
  5.         channelFactory = bootstrap.channelFactory;  
  6.         handler = bootstrap.handler;  
  7.         localAddress = bootstrap.localAddress;  
  8.         synchronized (bootstrap.options) {  
  9.             options.putAll(bootstrap.options);  
  10.         }  
  11.         synchronized (bootstrap.attrs) {  
  12.             attrs.putAll(bootstrap.attrs);  
  13.         }  
  14. }  
接着看代码一:

[java] view plain copy
  1. sbs.channel(NioServerSocketChannel.class);  
这个channel方法则是规定了这个ServerBootstrap的channel是啥,这里面维护了一个叫做channelFactory的东西,顾名思义,这是一个channel的工厂,我们传递的是NioServerSocketChannel这个类,那么这个channelFactory工厂创建出来的channel就是NioServerSocketChannel



去掉一些handler类,我们看:

[java] view plain copy
  1. ChannelFuture future = sbs.bind(port).sync();    
我们看bind方法

[java] view plain copy
  1. public ChannelFuture bind(int inetPort) {  
  2.         return bind(new InetSocketAddress(inetPort));  
  3. }  
  4.   
  5. public ChannelFuture bind(SocketAddress localAddress) {  
  6.         validate();  
  7.         if (localAddress == null) {  
  8.             throw new NullPointerException("localAddress");  
  9.         }  
  10.         return doBind(localAddress);  
  11. }  
  12.   
  13. private ChannelFuture doBind(final SocketAddress localAddress) {  
  14.         final ChannelFuture regFuture = initAndRegister();  
  15.         final Channel channel = regFuture.channel();  
  16.         if (regFuture.cause() != null) {  
  17.             return regFuture;  
  18.         }  
  19.   
  20.         final ChannelPromise promise;  
  21.         if (regFuture.isDone()) {  
  22.             promise = channel.newPromise();  
  23.             doBind0(regFuture, channel, localAddress, promise);  
  24.         } else {  
  25.             // Registration future is almost always fulfilled already, but just in case it's not.  
  26.             promise = new PendingRegistrationPromise(channel);  
  27.             regFuture.addListener(new ChannelFutureListener() {  
  28.                 @Override  
  29.                 public void operationComplete(ChannelFuture future) throws Exception {  
  30.                     doBind0(regFuture, channel, localAddress, promise);  
  31.                 }  
  32.             });  
  33.         }  
  34.   
  35.         return promise;  
  36. }  

最后调用了AbstractBootstrap(这个我们刚才做过处理,把bossGroup赋值了AbstractBootstrap的group,也就是说这个AbstractBootstrap获取到一个thread执行器了)

言归正传,我们看doBind方法:

(代码三)

[java] view plain copy
  1. final ChannelFuture regFuture = initAndRegister();  

[java] view plain copy
  1. final ChannelFuture initAndRegister() {  
  2.         final Channel channel = channelFactory().newChannel();  
  3.         try {  
  4.             init(channel);  
  5.         } catch (Throwable t) {  
  6.             channel.unsafe().closeForcibly();  
  7.             return channel.newFailedFuture(t);  
  8.         }  
  9.   
  10.         ChannelFuture regFuture = group().register(channel);  
  11.         if (regFuture.cause() != null) {  
  12.             if (channel.isRegistered()) {  
  13.                 channel.close();  
  14.             } else {  
  15.                 channel.unsafe().closeForcibly();  
  16.             }  
  17.         }  
  18.   
  19.         return regFuture;  
  20.     }  
好了,我们看到了channelFactory了,那么它new出来的channel当然就是NioServerSocketChannel

(代码四)

[java] view plain copy
  1. @Override  
  2.         public T newChannel() {  
  3.             try {  
  4.                 return clazz.newInstance();  
  5.             } catch (Throwable t) {  
  6.                 throw new ChannelException("Unable to create Channel from class " + clazz, t);  
  7.             }  
  8.         }  
这边要提及的是,我们创建NioServerSocketChannel的实例的时候,会触发它的父类AbstractChannel的构造函数:

[java] view plain copy
  1. protected AbstractChannel(Channel parent) {  
  2.         this.parent = parent;  
  3.         unsafe = newUnsafe();  
  4.         pipeline = new DefaultChannelPipeline(this);  
  5. }  
unsafe = newUnsafe()这个是我们需要关注的,unsafe看起来就很熟悉,不过此unsafe并不是juc包那个CAS的unsafe,我们看看它的抽象:

源码位于io.netty.channel.Channel的Unsafe

[java] view plain copy
  1. interface Unsafe {  
  2.         /** 
  3.          * Return the {@link SocketAddress} to which is bound local or 
  4.          * {@code null} if none. 
  5.          */  
  6.         SocketAddress localAddress();  
  7.   
  8.         /** 
  9.          * Return the {@link SocketAddress} to which is bound remote or 
  10.          * {@code null} if none is bound yet. 
  11.          */  
  12.         SocketAddress remoteAddress();  
  13.   
  14.         /** 
  15.          * Register the {@link Channel} of the {@link ChannelPromise} with the {@link EventLoop} and notify 
  16.          * the {@link ChannelFuture} once the registration was complete. 
  17.          */  
  18.         void register(EventLoop eventLoop, ChannelPromise promise);  

我列出部分代码的意思就是这个unsafe其实是束缚于Channel的,但也提供了channel的一些方法,比如register(EventLoop eventLoop, ChannelPromise promise)这个方法,将channel注册到eventLoop上去,这是很关键的,我们再回归到AbstractChannel的newUnsafe方法上来,追踪源代码最终发现:

[java] view plain copy
  1. @Override  
  2.     protected AbstractNioUnsafe newUnsafe() {  
  3.         return new NioMessageUnsafe();  
  4. }  

好了,最终NioServerSocketChannel这个channel对应的Unsafe是NioMessageUnsafe,关于AbstractChannel的newUnsafe这只是一个插曲(下文会用到),我们还是回到【代码三】

[java] view plain copy
  1. final Channel channel = channelFactory().newChannel();  
  2.   
  3. init(channel);  

init的方法,很重要,这里面规范了channel的一些属性,我们看看位于ServerBootstrap中的init方法

[java] view plain copy
  1. @Override  
  2.     void init(Channel channel) throws Exception {  
  3.         final Map<ChannelOption<?>, Object> options = options();  
  4.         synchronized (options) {  
  5.             channel.config().setOptions(options);  
  6.         }  
  7.   
  8.         final Map<AttributeKey<?>, Object> attrs = attrs();  
  9.         synchronized (attrs) {  
  10.             for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {  
  11.                 @SuppressWarnings("unchecked")  
  12.                 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();  
  13.                 channel.attr(key).set(e.getValue());  
  14.             }  
  15.         }  
  16.   
  17.         ChannelPipeline p = channel.pipeline();  
  18.         if (handler() != null) {  
  19.             p.addLast(handler());  
  20.         }  
  21.   
  22.         final EventLoopGroup currentChildGroup = childGroup;  
  23.         final ChannelHandler currentChildHandler = childHandler;  
  24.         final Entry<ChannelOption<?>, Object>[] currentChildOptions;  
  25.         final Entry<AttributeKey<?>, Object>[] currentChildAttrs;  
  26.         synchronized (childOptions) {  
  27.             currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));  
  28.         }  
  29.         synchronized (childAttrs) {  
  30.             currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));  
  31.         }  
  32.   
  33.         p.addLast(new ChannelInitializer<Channel>() {  
  34.             @Override  
  35.             public void initChannel(Channel ch) throws Exception {  
  36.                 ch.pipeline().addLast(new ServerBootstrapAcceptor(  
  37.                         currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));  
  38.             }  
  39.         });  
  40.     }  
因为channel这边有很多option,另外我们看到了childGroup(我们刚才赋值的workerGroup),childHandler也就是handlers,也就是channel配置了options,获取到线程执行器了,最后我们需要关注的就是channel中的ChannelPipeline中增加了一个ServerBootstrapAcceptor(后面再分析,这边就是说明一下,在channelPipeLine中有了ServerBootstrapAcceptor)


回到initAndRegister这个方法中来,init完了channel,最最关键的一步就是

[java] view plain copy
  1. ChannelFuture regFuture = group().register(channel);  

还是不忘初心,在NIO的编程中有一个很重要的步骤,我们可以将这个步骤写出来:

[java] view plain copy
  1. SocketChannel channel = SocketChannel.open();  
  2. channel.configureBlocking(false);  
  3. InetSocketAddress s = new InetSocketAddress("localhost"2000);  
  4. channel.connect(s);  
  5.   
  6. Selector selector = Selector.open();  
  7. channel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);  

这是一段很经典的纯的Java的NIO的的client代码。


这边我们看channel.register这行代码,我们需要将channel注册到selector上,并且传递自己感兴趣的事件参数,这样当有selector上有事件发生的是,就会通知注册的channel触发对应的事件


我们在分析netty的时候,我们知道在分析NioEventLoopGroup源码的时候,我们知道每一个NioEventLoopGroup都维护了一个selector,再后文中我们也分析了一个channel的创建过程,但是还没有进行selector和selector进行register


这边的group().register(channel)最后调用的是:

[java] view plain copy
  1. channel.unsafe().register(this, promise);  
回到一圈,我们有看到了unsafe,这个unsafe上文已经分析过了,是NioMessageUnsafe,register是它父类AbstractUnsafe完成的动作

我们也注意下register的入参,this指代的是SingleThreadEventLoop这个实例(其实我要的不是这个实例,而是这个实例中的selector(位于NioEventLoop.java中))


最后的注册动作是在AbstractNioChannel.java中完成的

[java] view plain copy
  1. @Override  
  2.     protected void doRegister() throws Exception {  
  3.         boolean selected = false;  
  4.         for (;;) {  
  5.             try {  
  6.                 selectionKey = javaChannel().register(eventLoop().selector, 0this);  
  7.                 return;  
  8.             } catch (CancelledKeyException e) {  
  9.                 if (!selected) {  
  10.                     // Force the Selector to select now as the "canceled" SelectionKey may still be  
  11.                     // cached and not removed because no Select.select(..) operation was called yet.  
  12.                     eventLoop().selectNow();  
  13.                     selected = true;  
  14.                 } else {  
  15.                     // We forced a select operation on the selector before but the SelectionKey is still cached  
  16.                     // for whatever reason. JDK bug ?  
  17.                     throw e;  
  18.                 }  
  19.             }  
  20.         }  
  21.     }  
这边我们要注意evetLoop就是我们刚才说的this,也就是SingleThreadEventLoop抽象类的具体实现,这边获取到了selector,javaChannel()这个方法就是

[java] view plain copy
  1. protected SelectableChannel javaChannel() {  
  2.         return ch;  
  3.     }  
[java] view plain copy
  1. private final SelectableChannel ch;  

估计这边大家要问这个ch是什么时候赋值的,请看【代码四】

在newInstant的时候创建NioServerSocketChannel实例的时候,进行了赋值,这边ch其实就是NioServerSocketChannel

好了,到此为止,我们基本分析了Netty的server端的启动过程,你也许会问server的thread貌似还没有start吧,其实不然,你可以仔细观察一下register0这个方法,是这么调用的:

[java] view plain copy
  1. try {  
  2.                     eventLoop.execute(new OneTimeTask() {  
  3.                         @Override  
  4.                         public void run() {  
  5.                             register0(promise);  
  6.                         }  
  7.                     });  
  8.                 } catch (Throwable t) {  
  9.                     logger.warn(  
  10.                             "Force-closing a channel whose registration task was not accepted by an event loop: {}",  
  11.                             AbstractChannel.this, t);  
  12.                     closeForcibly();  
  13.                     closeFuture.setClosed();  
  14.                     safeSetFailure(promise, t);  
  15. }  
这个eventLoop其实就是AbstractBootstrap的group,像注册这种动作也是一种事件,所以需要Bootstrap的自带的thread去做这个动作,最终会调用SingleThreadEventExecutor的execute的方法:

[java] view plain copy
  1. @Override  
  2.     public void execute(Runnable task) {  
  3.         if (task == null) {  
  4.             throw new NullPointerException("task");  
  5.         }  
  6.   
  7.         boolean inEventLoop = inEventLoop();  
  8.         if (inEventLoop) {  
  9.             addTask(task);  
  10.         } else {  
  11.             startThread();  
  12.             addTask(task);  
  13.             if (isShutdown() && removeTask(task)) {  
  14.                 reject();  
  15.             }  
  16.         }  
  17.   
  18.         if (!addTaskWakesUp && wakesUpForTask(task)) {  
  19.             wakeup(inEventLoop);  
  20.         }  
  21.     }  

最后会调用startThread方法,归于自然,归于本心,调用SingleThreadEventExecutor的

[java] view plain copy
  1. private void startThread() {  
  2.         if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {  
  3.             if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {  
  4.                 delayedTaskQueue.add(new ScheduledFutureTask<Void>(  
  5.                         this, delayedTaskQueue, Executors.<Void>callable(new PurgeTask(), null),  
  6.                         ScheduledFutureTask.deadlineNanos(SCHEDULE_PURGE_INTERVAL), -SCHEDULE_PURGE_INTERVAL));  
  7.                 thread.start();  
  8.             }  
  9.         }  
  10.     }  

thrad的start调用的方法就是我们刚才片段二种的

[java] view plain copy
  1. SingleThreadEventExecutor.this.run();  


好了,先分析这么多吧,我们进行总结一下,分析太多,我自己也记不过来

1)Netty的server端代码一开始初始化了两个EventLoopGroup,其实就是初始化EventLoop,每一个EventLoop的具体实现就是维护了一个任务队列,一个延迟任务队列,一个thread,并且每一个EventLoop都有一个属于自己的Executor执行器,这样做的好处就是每一个唯一的thread去不停的循环调用,去执行任务队列和延迟任务队列中的task,没有了上下文的切换们还要记得每一个EventLoop还初始化了一个selector,关于selector的创建,netty做了很大的优化,使其与CPU更加亲和

(中间还忘记分析了,CPU是2的倍数的时候,Netty的优化,大家可以自己看下)

2)关于serverBootstrap的初始化,主要就是做了channel的创建,channel的执行器的绑定,option属性的配置,绑定端口,这些配置好了之后就是channel和selector的绑定,绑定的时候,顺带启动一些AbstractBootstrap中的thread,让其进行无限循环中

3)关于细节

①serverBootstrap中在channelPipeline中偷偷地加了一个ServerBootstrapAcceptor

②serverBootstrap中的boss线程对应的unsafe对象是NioMessageUnsafe实例


阅读全文
0 0