Netty源码分析系列1——NIOEventLoopGroup的创建


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

转载:http://xw-z1985.iteye.com/blog/1924124

 

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

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

EventLoopGroup bossGroup = new NioEventLoopGroup();

 

NioEventLoopGroup的类关系图如下:



 构造方法执行过程如下:

 

Java代码   收藏代码
  1. // NioEventLoopGroup  
  2. public NioEventLoopGroup() {  
  3.         this(0);  
  4.     }  
  5.   
  6. public NioEventLoopGroup(int nThreads) {  
  7.         this(nThreads, null);  
  8.     }  
  9.   
  10. public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {  
  11.         this(nThreads, threadFactory, SelectorProvider.provider());  
  12.     }  
  13.   
  14. public NioEventLoopGroup(  
  15.             int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {  
  16.         super(nThreads, threadFactory, selectorProvider);  
  17.     }  

 看下父类MultithreadEventLoopGroup的构造方法

Java代码   收藏代码
  1. // MultithreadEventLoopGroup  
  2. protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
  3.         super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);  
  4.     }  

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

 

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

 

Java代码   收藏代码
  1. /** 
  2.     * Create a new instance. 
  3.     * 
  4.     * @param nThreads          the number of threads that will be used by this instance. 
  5.     * @param threadFactory     the ThreadFactory to use, or {@code null} if the default should be used. 
  6.     * @param args              arguments which will passed to each {@link #newChild(ThreadFactory, Object...)} call 
  7.     */  
  8.    protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
  9.        if (nThreads <= 0) {  
  10.            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));  
  11.        }  
  12.   
  13.        if (threadFactory == null) {  
  14.            threadFactory = newDefaultThreadFactory();  
  15.        }  
  16.   
  17.        children = new SingleThreadEventExecutor[nThreads];  
  18.        for (int i = 0; i < nThreads; i ++) {  
  19.            boolean success = false;  
  20.            try {  
  21.                children[i] = newChild(threadFactory, args);  
  22.                success = true;  
  23.            } catch (Exception e) {  
  24.                // TODO: Think about if this is a good exception type  
  25.                throw new IllegalStateException("failed to create a child event loop", e);  
  26.            } finally {  
  27.                if (!success) {  
  28.                    for (int j = 0; j < i; j ++) {  
  29.                        children[j].shutdownGracefully();  
  30.                    }  
  31.   
  32.                    for (int j = 0; j < i; j ++) {  
  33.                        EventExecutor e = children[j];  
  34.                        try {  
  35.                            while (!e.isTerminated()) {  
  36.                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);  
  37.                            }  
  38.                        } catch (InterruptedException interrupted) {  
  39.                            Thread.currentThread().interrupt();  
  40.                            break;  
  41.                        }  
  42.                    }  
  43.                }  
  44.            }  
  45.        }  
  46.   
  47.        final FutureListener<Object> terminationListener = new FutureListener<Object>() {  
  48.            @Override  
  49.            public void operationComplete(Future<Object> future) throws Exception {  
  50.                if (terminatedChildren.incrementAndGet() == children.length) {  
  51.                    terminationFuture.setSuccess(null);  
  52.                }  
  53.            }  
  54.        };  
  55.   
  56.        for (EventExecutor e: children) {  
  57.            e.terminationFuture().addListener(terminationListener);  
  58.        }  
  59.    }  

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

 

Java代码   收藏代码
  1. // NioEventLoopGroup  
  2.   protected EventExecutor newChild(  
  3.             ThreadFactory threadFactory, Object... args) throws Exception {  
  4.         return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);  
  5.     }  

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

 



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

 

接着看NioEventLoop的构造函数:

 

Java代码   收藏代码
  1. // NioEventLoop  
  2.  NioEven NioEventLoop tLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {  
  3.         super(parent, threadFactory, false);  
  4.         if (selectorProvider == null) {  
  5.             throw new NullPointerException("selectorProvider");  
  6.         }  
  7.         provider = selectorProvider;  
  8.         selector = openSelector();  
  9.     }  

 首先分析一下selector = openSelector()

 

 

Java代码   收藏代码
  1. // NioEventLoop  
  2.  private Selector openSelector() {  
  3.         final Selector selector;  
  4.         try {  
  5.             selector = provider.openSelector();  
  6.         } catch (IOException e) {  
  7.             throw new ChannelException("failed to open a new selector", e);  
  8.         }  
  9.   
  10.         if (DISABLE_KEYSET_OPTIMIZATION) {  
  11.             return selector;  
  12.         }  
  13.   
  14.         try {  
  15.             SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();  
  16.   
  17.             Class<?> selectorImplClass =  
  18.                     Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());  
  19.             selectorImplClass.isAssignableFrom(selector.getClass());  
  20.             Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");  
  21.             Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");  
  22.   
  23.             selectedKeysField.setAccessible(true);  
  24.             publicSelectedKeysField.setAccessible(true);  
  25.   
  26.             selectedKeysField.set(selector, selectedKeySet);  
  27.             publicSelectedKeysField.set(selector, selectedKeySet);  
  28.   
  29.             selectedKeys = selectedKeySet;  
  30.             logger.trace("Instrumented an optimized java.util.Set into: {}", selector);  
  31.         } catch (Throwable t) {  
  32.             selectedKeys = null;  
  33.             logger.trace("Failed to instrument an optimized java.util.Set into: {}", selector, t);  
  34.         }  
  35.   
  36.         return selector;  
  37.     }  

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

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

 

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

Java代码   收藏代码
  1. /** 
  2.     * Create a new instance 
  3.     * 
  4.     * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it 
  5.     * @param threadFactory     the {@link ThreadFactory} which will be used for the used {@link Thread} 
  6.     * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the 
  7.     *                          executor thread 
  8.     */  
  9.    protected SingleThreadEventExecutor(  
  10.            EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {  
  11.   
  12.        if (threadFactory == null) {  
  13.            throw new NullPointerException("threadFactory");  
  14.        }  
  15.   
  16.        this.parent = parent;  
  17.        this.addTaskWakesUp = addTaskWakesUp;  
  18.   
  19.        thread = threadFactory.newThread(new Runnable() {  
  20.            @Override  
  21.            public void run() {  
  22.                boolean success = false;  
  23.                updateLastExecutionTime();  
  24.                try {  
  25.                    SingleThreadEventExecutor.this.run();  
  26.                    success = true;  
  27.                } catch (Throwable t) {  
  28.                    logger.warn("Unexpected exception from an event executor: ", t);  
  29.                } finally {  
  30.                    if (state < ST_SHUTTING_DOWN) {  
  31.                        state = ST_SHUTTING_DOWN;  
  32.                    }  
  33.   
  34.                    // Check if confirmShutdown() was called at the end of the loop.  
  35.                    if (success && gracefulShutdownStartTime == 0) {  
  36.                        logger.error(  
  37.                                "Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +  
  38.                                SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called " +  
  39.                                "before run() implementation terminates.");  
  40.                    }  
  41.   
  42.                    try {  
  43.                        // Run all remaining tasks and shutdown hooks.  
  44.                        for (;;) {  
  45.                            if (confirmShutdown()) {  
  46.                                break;  
  47.                            }  
  48.                        }  
  49.                    } finally {  
  50.                        try {  
  51.                            cleanup();  
  52.                        } finally {  
  53.                            synchronized (stateLock) {  
  54.                                state = ST_TERMINATED;  
  55.                            }  
  56.                            threadLock.release();  
  57.                            if (!taskQueue.isEmpty()) {  
  58.                                logger.warn(  
  59.                                        "An event executor terminated with " +  
  60.                                        "non-empty task queue (" + taskQueue.size() + ')');  
  61.                            }  
  62.   
  63.                            terminationFuture.setSuccess(null);  
  64.                        }  
  65.                    }  
  66.                }  
  67.            }  
  68.        });  
  69.   
  70.        taskQueue = newTaskQueue();  
  71.    }  
  72.   
  73.    /** 
  74.     * Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a 
  75.     * {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking 
  76.     * calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant 
  77.     * implementation that does not support blocking operations at all. 
  78.     */  
  79.    protected Queue<Runnable> newTaskQueue() {  
  80.        return new LinkedBlockingQueue<Runnable>();  
  81.    }  

 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值