netty源碼分析(6)-NioEventLoop創建過程

前面幾章,在我們分析的時候註冊Selector相關代碼的時候,提到過一部分NioEventLoop的創建過程。接下來詳細分析。new NioEventLoopGroup();

    public NioEventLoopGroup(int nThreads, Executor executor) {
        //從jdk地層中獲取了一個SelectorProvider
        this(nThreads, executor, SelectorProvider.provider());
    }

    public NioEventLoopGroup(
            int nThreads, Executor executor, final SelectorProvider selectorProvider) {
        //接着提供了一種默認的SelectStrategy工廠
        this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
    }

    public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        //提供了一種拒絕執行的異常處理器
        super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }

    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        //如果沒有指定線程數,那麼就使用默認的值,通過斷點發現DEFAULT_EVENT_LOOP_THREADS的值是8
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
        // 提供了默認的EventExecutor選擇器工廠   
        //該值爲:new DefaultEventExecutorChooserFactory();
        this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
    }

最終走到了MultithreadEventExecutorGroup的構造方法。主要做了幾件事

  1. new ThreadPerTaskExecutor(newDefaultThreadFactory())
  2. 根據線程數初始化EventExecutor數組,並提供足夠的具體EventLoop,這裏是NioEventLoop
  3. 初始化chooser,提供不同的事件執行的選擇器,已選擇EventExecutor數組種的EventLoop
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
       //省略代碼

        if (executor == null) {
            //初始化executor : 每個任務的執行器
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
        
        children = new EventExecutor[nThreads];
        for (int i = 0; i < nThreads; i ++) {
            //實例化具體的NioEventLoop
            children[i] = newChild(executor, args);
            
        }
        //初始化 EventExecutorChooserFactory.EventExecutorChooser chooser
        chooser = chooserFactory.newChooser(children);

         //省略相關代碼
    }
  • new ThreadPerTaskExecutor(newDefaultThreadFactory())
    任務執行器給了一個默認的工廠,定義了該具體每個線程的名字,類似nioEventLoopGroup-2-1這樣的線程名字,第一個數字在初始化的時候便定義了爲poolId,第二個數字這是在執行newThread()的時候定義的nextIdThreadPerTaskExecutor還定義了execute方法。
public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
        //調用工廠具體的執行方法執行 該task: command
        threadFactory.newThread(command).start();
    }
}

關於poolIdnextId我們發現前者是靜態的,因此,每次new NioEventLoopGroup()的時候遞增,因此代表線程池,而後者並非靜態的,因此僅僅是調用遞增而已。

 private static final AtomicInteger poolId = new AtomicInteger();
 private final AtomicInteger nextId = new AtomicInteger();

跟進最終調用的是DefaultThreadFactory#newThread(),並且發現,結果是返回了FastThreadLocalThread,該線程爲netty自定義線程。執行的也是這類型的線程。因此們該對象每次執行任務(調用ThreadPerTaskExecutor#execute()),其實都創建了一個線程實體。

@Override
    public Thread newThread(Runnable r) {
        Thread t = newThread(new DefaultRunnableDecorator(r), prefix + nextId.incrementAndGet());
       //省略代碼
        return t;
    }

    protected Thread newThread(Runnable r, String name) {
        return new FastThreadLocalThread(threadGroup, r, name);
    }
  • 至於初始化chooser,線程選擇器,前面章節《Selector註冊》有提到過,其實就是分開兩種策略去循環使用EventExecutor數組。

  • 調用newChild()初始化NioEventLoop的時候,這裏創建並綁定了selector用於去輪詢註冊到它上面的一些連接。

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
        if (selectorProvider == null) {
            throw new NullPointerException("selectorProvider");
        }
        if (strategy == null) {
            throw new NullPointerException("selectStrategy");
        }
        provider = selectorProvider;
        final SelectorTuple selectorTuple = openSelector();
        selector = selectorTuple.selector;
        unwrappedSelector = selectorTuple.unwrappedSelector;
        selectStrategy = strategy;
    }

值得注意的是,父類構造方法SingleThreadEventLoop初始化了tailTasks。該隊列用於在外部線程執行一些netty任務的時候,判斷是否在NioEventLoop中,如果不在的話,則放到該隊列中去執行。講這些任務放到一個線程去執行。

    private final Queue<Runnable> tailTasks;
    protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
                                    boolean addTaskWakesUp, int maxPendingTasks,
                                    RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
        tailTasks = newTaskQueue(maxPendingTasks);
    }
    
    //由於本例NioEventLoop重寫了該方法,因此調用的子類
    protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
        return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
    }

    @Override
    protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
        // This event loop never calls takeTask()
        return PlatformDependent.newMpscQueue(maxPendingTasks);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章