netty原始碼分析-執行緒池

b10l07發表於2017-09-09

眾所周知,netty是一款效能非常出色的nio框架,作為dubbo等眾多優秀專案底層的資料傳輸框架,研究吃透它,對於我們今後的開發是絕對有益無害的,所以從今天開始我們就研究netty。本次分析基於netty4,請諸位看官自行下載jar包及原始碼。好了,我們今天說一下netty的執行緒池。
我們經常會看到netty的程式碼中有下面這一句。

EventLoopGroup workerGroup = new NioEventLoopGroup();

簡單的new了一個事件的處理組(也沒看官方怎麼解釋這個概念的,自己定義了一下吧,勿噴)。但他裡面所作的事情卻遠不止看到的這麼簡單。這也是我們閱讀原始碼的一個準則,不要忽略每一個你認為的不起眼的程式碼,也許他的作用是舉足輕重的。他的具體實現

### io.netty.channel.nio.NioEventLoopGroup#NioEventLoopGroup()
/**
 * Create a new instance using the default number of threads, the default {@link ThreadFactory} and
 * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
 */
public NioEventLoopGroup() {
    this(0);
}

### io.netty.channel.MultithreadEventLoopGroup#MultithreadEventLoopGroup(int, java.util.concurrent.Executor, java.lang.Object...)
/**
 * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
 */
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

### MultithreadEventLoopGroup.java:39
static {
    DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
            "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

    if (logger.isDebugEnabled()) {
        logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
    }
}

### 表示程式碼出自的類及方法名,因為他們的相關性很大,所以我就放到同一個程式碼塊中,防止思維跳躍太大,大家跟不上節奏。雖然現在初始化的時候設定了執行緒數為0,但是並不是最後的結果,經過了諸多的建構函式的呼叫及父類建構函式的引用,在這裡做了一個轉化,當為0時,會取DEFAULT_EVENT_LOOP_THREADS的值,而他的值,他取的是,如果設定io.netty.eventLoopThreads的值就取這個值,沒有設定的話,會取預設值可用核數的兩倍,同1比較去一個最大的進行賦值。最後我們到達了最好的建構函式

### io.netty.util.concurrent.MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, java.util.concurrent.Executor, io.netty.util.concurrent.EventExecutorChooserFactory, java.lang.Object...)

/**
 * Create a new instance.
 *
 * @param nThreads          the number of threads that will be used by this instance.
 * @param executor          the Executor to use, or {@code null} if the default should be used.
 * @param chooserFactory    the {@link EventExecutorChooserFactory} to use.
 * @param args              arguments which will passed to each {@link #newChild(Executor, Object...)} call
 */
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                        EventExecutorChooserFactory chooserFactory, Object... args) {
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
    }

    if (executor == null) {   //如何executor為空,那麼設定預設執行器為ThreadPerTaskExecutor
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }

    children = new EventExecutor[nThreads];   //MultithreadEventExecutorGroup是一個總的管理的類,具體和執行緒相關的都交給他的children進行處理,是一個EventExecutor的陣列

    for (int i = 0; i < nThreads; i ++) {
        boolean success = false;
        try {
            children[i] = newChild(executor, args);   //初始化每一個EventExecutor的例項,下面會有詳細解釋
            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) {
                        // Let the caller handle the interruption.
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
    }

    chooser = chooserFactory.newChooser(children);  //建立執行緒的選擇器,選擇是有哪個執行緒來處理

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

    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);   //將這些子處理器設定為只讀,不能新增
}

在上面的程式碼中都有關鍵步驟的註釋,總的來說就是最後的髒活累活都不是這個Group乾的,都交給自己內部的children來幹,都交給EventExecutor來幹,我們看一下這個EventExecutor是如何例項化的

### io.netty.channel.nio.NioEventLoopGroup#newChild

@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}

### io.netty.channel.nio.NioEventLoop#NioEventLoop
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;
}

EventExecutor是使用NioEventLoop進行初始化的,這個NioEventLoop是SingleThreadEventLoop的子類,所以super呼叫的是SingleThreadEventLoop的構造方法


/**
 * Create a new instance
 *
 * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
 * @param executor          the {@link Executor} which will be used for executing
 * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
 *                          executor thread
 * @param maxPendingTasks   the maximum number of pending tasks before new tasks will be rejected.
 * @param rejectedHandler   the {@link RejectedExecutionHandler} to use.
 */
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                    boolean addTaskWakesUp, int maxPendingTasks,
                                    RejectedExecutionHandler rejectedHandler) {
    super(parent);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = ObjectUtil.checkNotNull(executor, "executor");
    taskQueue = newTaskQueue(this.maxPendingTasks);    //設定任務的處理佇列,後續任務會新增到這裡面
    rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

OK,每一個處理子事件處理器都會有一個任務的佇列。目前為止執行緒池的初始化就告一段落了,感覺沒過癮,我們們就下一篇見。

相關文章