Netty4 服务端启动源码分析-线程的创建

来源:互联网 发布:大学生it培训机构 编辑:程序博客网 时间:2024/06/03 20:17

原文链接:http://xw-z1985.iteye.com/blog/1925013


本文分析Netty中boss和worker的线程的创建过程:

以下代码是服务端的启动代码,线程的创建就发生在其中。

EventLoopGroup bossGroup = new NioEventLoopGroup();

 

NioEventLoopGroup的类关系图如下:



 构造方法执行过程如下:

// NioEventLoopGroup  public NioEventLoopGroup() {          this(0);      }    public NioEventLoopGroup(int nThreads) {          this(nThreads, null);      }    public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {          this(nThreads, threadFactory, SelectorProvider.provider());      }    public NioEventLoopGroup(              int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {          super(nThreads, threadFactory, selectorProvider);      } 

看下父类MultithreadEventLoopGroup的构造方法

// MultithreadEventLoopGroup  protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {          super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);      } 

注:如果没有指定创建的线程数量,则默认创建的线程个数为DEFAULT_EVENT_LOOP_THREADS,该数值为:处理器数量x2

 

再来看MultithreadEventLoopGroup的父类MultithreadEventExecutorGroup的构造方法

 

/**     * Create a new instance.     *     * @param nThreads          the number of threads that will be used by this instance.     * @param threadFactory     the ThreadFactory to use, or {@code null} if the default should be used.     * @param args              arguments which will passed to each {@link #newChild(ThreadFactory, Object...)} call     */     protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {         if (nThreads <= 0) {             throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));         }           if (threadFactory == null) {             threadFactory = newDefaultThreadFactory();         }           children = new SingleThreadEventExecutor[nThreads];         for (int i = 0; i < nThreads; i ++) {             boolean success = false;             try {                 children[i] = newChild(threadFactory, args);                 success = true;             } catch (Exception e) {                 // TODO: Think about if this is a good exception type                 throw new IllegalStateException("failed to create a child event loop", e);             } finally {                 if (!success) {                     for (int j = 0; j < i; j ++) {                         children[j].shutdownGracefully();                     }                       for (int j = 0; j < i; j ++) {                         EventExecutor e = children[j];                         try {                             while (!e.isTerminated()) {                                 e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);                             }                         } catch (InterruptedException interrupted) {                             Thread.currentThread().interrupt();                             break;                         }                     }                 }             }         }           final FutureListener<Object> terminationListener = new FutureListener<Object>() {             @Override             public void operationComplete(Future<Object> future) throws Exception {                 if (terminatedChildren.incrementAndGet() == children.length) {                     terminationFuture.setSuccess(null);                 }             }         };           for (EventExecutor e: children) {             e.terminationFuture().addListener(terminationListener);         }     } 

变量children就是用来存放创建的线程的数组,里面每一个元素都通过children[i] = newChild(threadFactory, args)创建。而newChild方法则由子类NioEventLoopGroup实现

 

// NioEventLoopGroup    protected EventExecutor newChild(              ThreadFactory threadFactory, Object... args) throws Exception {          return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);      }  

每个元素的真实类型为NioEventLoop,而NioEventLoop的类关系图如下

 



 (注:其实有点变态的,譬如EventLoop继承EventLoopGroup,不知道是啥原因,仅仅是因为EventLoop里有个方法parent(),返回EventLoopGroup这个功能吗?后续待确认)

 

接着看NioEventLoop的构造函数:

// NioEventLoop   NioEven NioEventLoop tLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {          super(parent, threadFactory, false);          if (selectorProvider == null) {              throw new NullPointerException("selectorProvider");          }          provider = selectorProvider;          selector = openSelector();      }  

首先分析一下selector = openSelector()

// NioEventLoop   private Selector openSelector() {          final Selector selector;          try {              selector = provider.openSelector();          } catch (IOException e) {              throw new ChannelException("failed to open a new selector", e);          }            if (DISABLE_KEYSET_OPTIMIZATION) {              return selector;          }            try {              SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();                Class<?> selectorImplClass =                      Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());              selectorImplClass.isAssignableFrom(selector.getClass());              Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");              Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");                selectedKeysField.setAccessible(true);              publicSelectedKeysField.setAccessible(true);                selectedKeysField.set(selector, selectedKeySet);              publicSelectedKeysField.set(selector, selectedKeySet);                selectedKeys = selectedKeySet;              logger.trace("Instrumented an optimized java.util.Set into: {}", selector);          } catch (Throwable t) {              selectedKeys = null;              logger.trace("Failed to instrument an optimized java.util.Set into: {}", selector, t);          }            return selector;      }  

这里对sun.nio.ch.SelectorImpl中的selectedKeys和publicSelectedKeys做了优化,NioEventLoop中的变量selectedKeys的类型是SelectedSelectionKeySet,有哪些优化呢?(内部用两个数组存储?初始分配数组大小置为1024避免频繁扩容?当大小超过1024时,对数组进行双倍扩容?)。

       利用反射,当注册到selector中的selectionKey已准备就绪时,selectedKeys中的元素就不会为空,后面会根据selectedKeys进行分发。

 

最后分析super(parent, threadFactory, false),即父类SingleThreadEventExecutor的构造函数

/**     * Create a new instance     *     * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it     * @param threadFactory     the {@link ThreadFactory} which will be used for the used {@link Thread}     * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the     *                          executor thread     */     protected SingleThreadEventExecutor(             EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {           if (threadFactory == null) {             throw new NullPointerException("threadFactory");         }           this.parent = parent;         this.addTaskWakesUp = addTaskWakesUp;           thread = threadFactory.newThread(new Runnable() {             @Override             public void run() {                 boolean success = false;                 updateLastExecutionTime();                 try {                     SingleThreadEventExecutor.this.run();                     success = true;                 } catch (Throwable t) {                     logger.warn("Unexpected exception from an event executor: ", t);                 } finally {                     if (state < ST_SHUTTING_DOWN) {                         state = ST_SHUTTING_DOWN;                     }                       // Check if confirmShutdown() was called at the end of the loop.                     if (success && gracefulShutdownStartTime == 0) {                         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 {                             synchronized (stateLock) {                                 state = ST_TERMINATED;                             }                             threadLock.release();                             if (!taskQueue.isEmpty()) {                                 logger.warn(                                         "An event executor terminated with " +                                         "non-empty task queue (" + taskQueue.size() + ')');                             }                               terminationFuture.setSuccess(null);                         }                     }                 }             }         });           taskQueue = newTaskQueue();     }       /**     * Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a     * {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking     * calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant     * implementation that does not support blocking operations at all.     */     protected Queue<Runnable> newTaskQueue() {         return new LinkedBlockingQueue<Runnable>();     }  

boss线程就在此处创建:thread = threadFactory.newThread(new Runnable()

同时也创建了线程的任务队列,是一个LinkedBlockingQueue结构。

SingleThreadEventExecutor.this.run()由子类NioEventLoop实现,后面的文章再进行分析

 

总结:

EventLoopGroup bossGroup = new NioEventLoopGroup()发生了以下事情:

      1、 为NioEventLoopGroup创建数量为:处理器个数 x 2的,类型为NioEventLoop的实例。每个NioEventLoop实例 都持有一个线程,以及一个类型为LinkedBlockingQueue的任务队列

      2、线程的执行逻辑由NioEventLoop实现

      3、每个NioEventLoop实例都持有一个selector,并对selector进行优化。


0 0
原创粉丝点击